
A twelve-year-old Salesforce org doesn't contain twelve years of configuration.
It contains twelve years of decisions.
Some were documented. Some were temporary fixes that became permanent. Some were created by admins who left years ago. Others were Visualforce pages, JavaScript buttons, old URL patterns, integrations, permission assumptions, and custom workflows that had quietly become business-critical.
That was the real challenge behind our Classic to Lightning migration.
At first, the project sounded simple:
Salesforce Classic
↓
Enable Lightning
↓
Fix a few pages
↓
Train users
↓
Done
The actual process looked more like:
Inventory
↓
Classify legacy customizations
↓
Identify Lightning gaps
↓
Modernize critical workflows
↓
Test permissions and integrations
↓
Roll out gradually
↓
Measure adoption
↓
Remove remaining Classic dependencies
The migration wasn't primarily a UI upgrade.
It was an archaeology project.
1. The First Thing That Broke Was Our Estimate
We initially counted obvious customizations:
- Visualforce pages
- Apex classes
- Custom objects
- Workflows
- JavaScript buttons
- Integrations
That gave us an inventory.
It did not give us an accurate estimate.
One Visualforce page might be a simple form.
Another might depend on:
Visualforce
+
Custom JavaScript
+
Apex controller
+
URL parameters
+
Profile-specific behavior
+
External API
Both count as one page.
They are completely different migration tasks.
We stopped estimating by component count and started asking:
Which business workflow depends on this customization?
That produced a much more realistic migration plan.
2. We Inventoried Behavior, Not Just Metadata
A long-lived Salesforce org can contain technically valid metadata that nobody actively understands.
We classified important customizations as:
KEEP
MIGRATE
REPLACE
REMOVE
INVESTIGATE
For each one, we asked:
Who uses it?
Which profiles or permission sets need it?
Which record types depend on it?
Does it invoke Apex?
Does it depend on Classic navigation?
Does an integration call it?
What happens if we remove it?
That final question uncovered several supposedly unused features.
They were not unused.
They were simply used rarely.
That distinction matters in a migration.
3. JavaScript Buttons Were an Early Warning
Classic-era JavaScript buttons often hide far more business logic than their UI suggests.
A button labeled:
Create Renewal
might actually:
Read current record
↓
Validate fields
↓
Build parameters
↓
Navigate to another page
↓
Trigger downstream automation
The button looked simple.
The implementation was effectively a small application.
Moving to Lightning forced us to decide whether each behavior should become:
Quick Action
Flow
Lightning Web Component
Apex-backed action
Standard Salesforce functionality
The positive part was that we stopped carrying forward old JavaScript simply because it already existed.
Migration became an opportunity to move critical business behavior into cleaner, supported platform patterns.
4. URL Hacks Had to Be Treated as Technical Debt
Classic-era implementations often accumulate hard-coded URL assumptions.
Conceptually:
/001/e?someParameter=value
or custom navigation logic that depends on a specific page structure.
These patterns can become fragile when the experience changes.
So we searched more than code.
We reviewed:
- Buttons
- Links
- Visualforce
- JavaScript
- Apex-generated URLs
- Email templates
- Integration responses
- Internal documentation
This produced one of the recurring lessons of the Classic to Lightning migration:
A UI migration can break code that doesn't look like UI code.
5. Visualforce Didn't Automatically Mean "Rewrite It"
The right question wasn't:
Do we have Visualforce?
It was:
How does this particular Visualforce page behave inside Lightning?
Some pages could continue working usefully.
Others exposed problems involving:
- Navigation
- Styling
- JavaScript assumptions
- Page dimensions
- Modal behavior
- Record context
- Browser behavior
Instead of rewriting everything, we classified each page.
Visualforce page
↓
Still useful and compatible?
├── YES → Keep temporarily
│
└── NO
↓
Modern replacement
That kept the project focused on real risk instead of creating unnecessary development work.
6. We Didn't Rewrite Everything to LWC
Once Lightning Web Components entered the discussion, another tempting strategy appeared:
Rewrite every customization.
That would have dramatically increased scope without necessarily improving the business outcome.
Instead, we asked:
Does this component genuinely need replacement?
Is it business-critical?
Is the current implementation difficult to maintain?
Is the workflow changing anyway?
Can standard Salesforce functionality now replace it?
For older orgs, Salesforce migration and modernization is broader than replacing Visualforce or Aura with LWC. It can also involve reviewing Apex, integrations, permissions, testing practices, deployment workflows, and technical debt before deciding what should actually be rebuilt.
Our target became:
Minimum custom code
+
Supported platform patterns
+
Required business behavior
rather than:
Maximum amount of new Lightning code
That kept the migration more controlled.
7. Record Pages Changed More Than the Look
Classic encouraged us to think primarily in terms of page layouts.
Lightning introduced a broader record-page experience.
A user might now interact with:
Record details
Tabs
Related lists
Custom components
Highlights
Activity
Conditional visibility
Utility components
That flexibility is valuable.
It also makes it easy to build pages that do too much.
Our first Lightning pages were too heavy because we tried to put every useful component in one place.
We started asking:
Does every user need this component?
Does it need to load immediately?
Can it live behind a tab?
Can standard functionality replace it?
Is this Apex call actually necessary?
A good Lightning page isn't the page with the most features.
It is the page that helps the user complete the next task quickly.
8. Permissions Exposed Hidden Assumptions
Testing only as System Administrator gave us false confidence.
Admin testing said:
It works.
Real users said:
I can't see it.
or:
I can see it, but I can't use it.
The difference often came from:
- Object permissions
- Field-level security
- Apex access
- Record types
- Permission sets
- App access
- Component visibility
- Custom permissions
So we created explicit test personas:
Sales Rep
Sales Manager
Service Agent
Operations
Finance
Administrator
Integration User
Every critical workflow had to work with the permissions of the person who actually performs it.
9. Navigation Was Part of the Business Process
Long-time users had muscle memory.
They knew:
Click tab
Open list
Choose view
Open record
Click button
Lightning sometimes changed that path.
At first, this looked like a training problem.
Sometimes it was.
Other times it revealed processes that had always been inefficient but had become familiar.
Instead of reproducing every Classic click path, we asked:
What is the user actually trying to accomplish?
That led to better navigation design and cleaner user workflows.
10. Integrations Needed Testing Too
Some backend integrations using Salesforce APIs were largely unaffected by the UI change.
Others were not.
Over twelve years, external systems may begin relying on assumptions about:
URLs
Rendered pages
Authentication flow
Record creation sequence
Browser redirects
Button behavior
So our integration inventory included:
- REST and SOAP integrations
- Middleware
- Connected apps
- Scheduled jobs
- Browser automation
- Email-driven processes
- Webhooks
- Apex callouts
- External links
The lesson was simple:
Classic-to-Lightning testing should not involve only admins and frontend developers.
Anything connected to a business workflow deserves regression testing.
11. Reports and Dashboards Needed Cleanup
Reports didn't necessarily break because the UI changed.
But migration gave us a reason to review which reports still mattered.
A twelve-year-old org can easily contain:
Sales Pipeline
Sales Pipeline New
Sales Pipeline V2
Sales Pipeline Final
Sales Pipeline FINAL USE THIS
We reviewed:
- Critical reports
- Dashboard visibility
- Folder permissions
- Filters
- Subscriptions
- Drill-down behavior
- Links from other workflows
Not every piece of historical configuration needed to become part of the new experience.
Migration was also a cleanup opportunity.
12. Some Features Were Different, Not Broken
One important mindset shift was accepting that Lightning does not need to behave exactly like Classic.
The wrong question is:
How do we recreate the exact Classic workflow?
A better question is:
What is the supported Lightning way to achieve the same business outcome?
Sometimes the implementation is different.
That is fine.
A migration should preserve business behavior.
It does not need to preserve every historical technical decision.
13. We Used Sandboxes as Migration Laboratories
Production users should not be the first people to discover compatibility issues.
Our cycle became:
Inventory
↓
Configure or modernize
↓
Deploy to sandbox
↓
Test workflows
↓
Test user roles
↓
Collect feedback
↓
Fix
↓
Repeat
This was especially valuable for:
- Visualforce
- Lightning pages
- Apex
- Flows
- Custom actions
- Permissions
- Integrations
- Navigation
The goal was for production rollout to become increasingly uneventful.
That is generally a good sign.
14. We Rolled Out by User Group
A twelve-year-old Salesforce org has different types of users.
Sales may use Salesforce all day.
Finance may use only a handful of workflows.
Operations might depend heavily on a few deeply customized screens.
So instead of:
Migration day
→ Everyone switches
we used:
Migration team
↓
Power users
↓
Pilot department
↓
Additional teams
↓
Broader rollout
This helped us separate:
Actual defect
Missing functionality
Permission issue
Training problem
Preference for Classic
Those are very different issues and need different responses.
15. User Adoption Became a Technical Signal
If users kept returning to Classic, we didn't immediately conclude:
They don't like change.
We investigated.
Maybe:
One workflow is missing
A page is too slow
An action is difficult to find
Permissions are wrong
Training missed a scenario
A Classic dependency still exists
User behavior became another source of migration telemetry.
If users had a legitimate reason to return to Classic, the migration was not finished.
16. The Migration Workflow That Worked Better
Eventually, our process became:
1. Inventory critical business workflows
2. Identify who uses each workflow
3. Map Classic customizations and dependencies
4. Classify each item:
Keep / Migrate / Replace / Remove
5. Build representative user personas
6. Design Lightning pages intentionally
7. Modernize only where needed
8. Test integrations and automation
9. Test every critical workflow by role
10. Pilot with real users
11. Fix defects and usability gaps
12. Expand rollout
13. Monitor adoption
14. Remove remaining Classic dependencies
A structured Salesforce Classic to Lightning migration should begin with an org audit covering Visualforce, Aura, JavaScript buttons, hard-coded URLs, permissions, integrations, and role-specific workflows before the actual rollout begins.
That planning work matters far more than simply enabling Lightning.
What Actually Took the Time
Looking back, the project was not:
Enable Lightning
+
Fix Visualforce
It was:
Understand twelve years of behavior
↓
Classify customizations
↓
Identify unsupported assumptions
↓
Modernize high-risk workflows
↓
Redesign important pages
↓
Revalidate permissions
↓
Retest integrations
↓
Test by role
↓
Train users
↓
Measure adoption
↓
Remove remaining Classic dependencies
The UI change was the visible part.
The dependency cleanup underneath it was the real migration.
A Practical Classic to Lightning Migration Checklist
Before rollout:
[ ] Critical workflows inventoried
[ ] Visualforce pages reviewed
[ ] JavaScript buttons reviewed
[ ] Classic URL assumptions reviewed
[ ] Custom navigation reviewed
[ ] Lightning pages intentionally designed
[ ] Heavy pages profiled
[ ] Apex-backed components tested
[ ] Integrations regression-tested
[ ] Profiles and permission sets reviewed
[ ] Field-level security tested
[ ] Reports and dashboards validated
[ ] Representative user personas defined
[ ] Role-based UAT completed
[ ] Training covers real workflows
After rollout:
[ ] Adoption monitored
[ ] Remaining Classic usage investigated
[ ] User feedback categorized
[ ] Performance issues measured
[ ] Missing workflows addressed
[ ] Redundant customizations removed
[ ] Dead reports/components cleaned up
[ ] Classic dependencies reduced
[ ] Classic access restricted when appropriate
The Biggest Lesson
The biggest surprise wasn't simply that things broke.
It was what broke.
We expected:
Visualforce
Custom JavaScript
Old components
We also found:
User habits
Navigation assumptions
Permission assumptions
Integration assumptions
Reporting clutter
Page-performance issues
Undocumented workflows
Years of technical debt
That is why migrating a twelve-year-old Salesforce org is not simply a user-interface project.
It is an opportunity to ask:
Which parts of the last twelve years still deserve to exist?
We didn't want Lightning to become:
Classic
+
new interface
+
all existing technical debt
We wanted:
Required business behavior
+
cleaner supported patterns
+
simpler pages
+
better-understood permissions
+
tested integrations
+
fewer legacy dependencies
A successful Classic to Lightning migration was not the moment Lightning was enabled.
It was the moment users could complete their work confidently in Lightning without having a business reason to return to Classic.
Top comments (0)