On this page
In short
- Inventory the file before designing anything: sheets or tables, formulas, macros and VBA, queries, reports, and every person and file that depends on it.
- Treat the data migration as its own piece of work with scripts, a mapping document and a reconciliation report, rehearsed more than once.
- Rebuild formulas and VBA as server-side rules, and use the old file as the test oracle: same inputs, same answers.
- Pick a cutover approach deliberately, make the old file read-only on the day, and keep an export to Excel so people don't rebuild the spreadsheet on the side.
Signs the file has outgrown itself
Spreadsheets and Access databases are good tools. Departments reach for them because they can start today without asking anyone. The trouble starts when the file becomes a shared system without being treated like one: several people depend on it, other processes read from it, and nobody can change it safely.
- People wait for each other. The file is locked, copies are emailed around, or someone merges versions at the end of the week.
- One person understands it. The macros, the hidden sheets or the Access queries only make sense to whoever wrote them.
- Mistakes are silent. A pasted value replaces a formula, a filter hides rows, or a lookup quietly returns the wrong match, and nobody notices until a report is wrong.
- It's hitting hard limits. An Access database file can't grow past 2 GB, and an Excel worksheet stops at 1,048,576 rows. Long before either, large shared files on a network drive can become slow and prone to corruption.
- Audit and access questions have no answer. Who changed this value, when, and who is allowed to see the file at all?
- Other systems depend on it. Reports, mail merges or other workbooks link to it, so a renamed column breaks something elsewhere.
Before committing to a custom build, check whether something you already own fits. Microsoft Lists, Power Apps or a module in an existing system can be the right answer for a simple list with a form. Our guide to custom web apps vs. low-code walks through that decision. A custom web app tends to earn its place when the logic is real, other systems need the data, or the process needs permissions and an audit trail that a shared file can't give you. For documents approved by email from a shared drive, see our guide to a simple document approval workflow app.
Inventory what the file actually does
The file's visible purpose is rarely all of it. A workbook that "tracks supplier corrective actions" may also calculate due dates, color-code overdue items, feed a monthly chart that goes to leadership, and hold a hidden sheet of lookup values another workbook reads. Anything missed here turns into a surprise after cutover.
What to inventory in a spreadsheet or Access database before replacing it
Data
- Where it hides
- Sheets and tables, including hidden sheets, very hidden sheets and old tabs nobody deletes
- Why it matters
- Defines the data model and what has to be migrated
Calculations
- Where it hides
- Formulas, named ranges, Access queries and calculated fields
- Why it matters
- Business rules the new app must reproduce exactly
Automation
- Where it hides
- VBA modules, Access macros, buttons and form events
- Why it matters
- Often the least documented and most important logic
Validation
- Where it hides
- Data validation lists, conditional formatting, input masks, required fields
- Why it matters
- Rules users rely on without thinking of them as rules
Meaning in formatting
- Where it hides
- Colors, bold rows, comments and notes
- Why it matters
- A red row may be a status that exists nowhere else
Outputs
- Where it hides
- Pivot tables, charts, printed reports, Access reports, mail merges
- Why it matters
- The reports people will ask for on day one
Connections
- Where it hides
- Links to other workbooks, Power Query, ODBC links to databases, linked Access tables
- Why it matters
- Systems that break when the file changes or disappears
People
- Where it hides
- Who edits, who only reads, who receives exports or screenshots
- Why it matters
- Roles, permissions and the people to involve in testing
| Look for | Where it hides | Why it matters |
|---|---|---|
| Data | Sheets and tables, including hidden sheets, very hidden sheets and old tabs nobody deletes | Defines the data model and what has to be migrated |
| Calculations | Formulas, named ranges, Access queries and calculated fields | Business rules the new app must reproduce exactly |
| Automation | VBA modules, Access macros, buttons and form events | Often the least documented and most important logic |
| Validation | Data validation lists, conditional formatting, input masks, required fields | Rules users rely on without thinking of them as rules |
| Meaning in formatting | Colors, bold rows, comments and notes | A red row may be a status that exists nowhere else |
| Outputs | Pivot tables, charts, printed reports, Access reports, mail merges | The reports people will ask for on day one |
| Connections | Links to other workbooks, Power Query, ODBC links to databases, linked Access tables | Systems that break when the file changes or disappears |
| People | Who edits, who only reads, who receives exports or screenshots | Roles, permissions and the people to involve in testing |
Sit with the people who use the file and watch them do the job. Ask what they do when something goes wrong, what they check before sending a report, and what they wish the file did. The workarounds they describe are requirements.
Design the data model, then clean the data
A spreadsheet usually stores one wide row per thing, with repeated columns such as "Action 1", "Action 2", "Action 3". A web app's database should store those as related records, with lists of values in their own tables. That change is what makes reporting, permissions and history possible later.
- Free text to picklists. A "Supplier" column with twelve spellings of the same company becomes a reference to one supplier record.
- Repeated columns to child rows. "Action 1" to "Action 5" become a list of actions, each with an owner and a date.
- Dates and numbers stored as text. Values such as "TBD", "3/4" or "approx 40" need a rule: convert, flag or leave blank with a note.
- Meaning in color or comments. Turn it into a real field, such as a status or a reason.
- Duplicates and orphans. Decide which record wins, and what happens to rows that reference something that no longer exists.
- Identifiers. Keep the old row number or record ID on each migrated record, so anyone can trace it back to the file.
The new database is usually SQL Server or PostgreSQL, often on infrastructure you already run. If the app also needs data from an existing system, our guide to integrating two business systems when one vendor's API is poor covers keeping the two in step.
Treat the migration as repeatable code
The worst migrations are done once, by hand, on the night of cutover. A better migration is a script that reads the file, applies the cleanup and mapping rules, loads the new database and produces a reconciliation report. It runs as many times as needed: on a copy early in the project, again after each round of feedback, and a final time at cutover.
The migration runs against a copy of the file until cutover. The original is never edited by the migration.
What a reconciliation report should show
- Row counts per source sheet or table, and record counts per new table.
- Totals of key numbers (quantities, amounts, hours) in the source and in the new database.
- Counts by status, so open items in the file equal open items in the app.
- Every row that failed a rule, with the reason, for the department to fix or accept.
- A sample of records checked by hand against the file by someone from the department.
Rebuild formulas and VBA as tested rules
A formula copied into a new app is still a formula nobody can see. Rebuild each calculation as a named rule on the server, where it applies to every screen, import and API call the same way, and write down what it does in plain language.
- Use the old file as the oracle. Take a set of real rows, run them through the file and through the new rule, and compare the results. Differences are either a bug in the new rule or a bug in the old file that the department needs to decide on.
- Watch for spreadsheet behavior. Rounding, blank cells treated as zero, text that looks like numbers, and date serial numbers all behave differently in a database and code. Decide each one explicitly.
- Replace macros with features. A VBA button that emails a report becomes a scheduled report or a notification; a macro that copies rows to an archive sheet becomes a status and a filter.
- Keep validation, and make it stricter at entry. Required fields, allowed values and ranges are checked when the record is saved, not discovered at month end.
Choosing a cutover approach
Cutover approaches for replacing a department file with a web app
Freeze and switch
- How it works
- Stop edits to the file, run the final migration, reconcile, and open the app
- Good fit when
- The data is small enough to migrate in a few hours and one team uses it
Short parallel run
- How it works
- People enter work in both for an agreed period and compare outputs
- Good fit when
- The calculations are critical and the team can afford the double entry for a short time
Phased by team or site
- How it works
- One group moves first; others follow once it's stable
- Good fit when
- Several teams or plants use their own copies of the file
New records only
- How it works
- New work starts in the app; open items finish in the old file, which is then archived
- Good fit when
- Records have a short life and migrating history isn't worth the cleanup
| Approach | How it works | Good fit when |
|---|---|---|
| Freeze and switch | Stop edits to the file, run the final migration, reconcile, and open the app | The data is small enough to migrate in a few hours and one team uses it |
| Short parallel run | People enter work in both for an agreed period and compare outputs | The calculations are critical and the team can afford the double entry for a short time |
| Phased by team or site | One group moves first; others follow once it's stable | Several teams or plants use their own copies of the file |
| New records only | New work starts in the app; open items finish in the old file, which is then archived | Records have a short life and migrating history isn't worth the cleanup |
- Rehearse the full migration on a recent copy, and time it.
- Agree a go or no-go check: the reconciliation report is clean or its exceptions are accepted.
- Announce the freeze time, and who to call on the day.
- Stop edits to the file, run the final migration and reconcile.
- Open the app, and make the old file read-only rather than deleting it.
- Fix links: bookmarks, shortcuts, and any workbook or report that read from the old file.
- Archive the old file with a note saying where the data now lives.
Our sample written scope shows how the data sources, the migration and the acceptance checks for a project like this are written down before a fixed price.
Making the change stick
- Involve the file's owner from the start. The person who built the spreadsheet knows its rules best and becomes the new app's best advocate if they help shape it.
- Make the app faster than the file for the common task. Sensible defaults, remembered filters and fewer clicks for the thing people do fifty times a day.
- Sign in with company accounts. Single sign-on and roles replace the shared file password. Our guide to SSO and least privilege for internal apps covers the design.
- Give the app an owner after launch. Someone decides on changes to picklists, rules and reports, instead of the department starting a new side spreadsheet.
- Watch for shadow copies. If people export and keep working in Excel, find out what the app is missing.
Have a file that's become a system?
Send us a description of the workbook or Access database and who depends on it. On a scoping call we'll talk through the data, the logic, the cutover and what a fixed-price build would cover.
Not ready to talk yet? Draft a project brief first
Checklist before you start
Take this to the department and IT
- A copy of the file, including hidden sheets, macros, queries and reports.
- A list of everyone who edits it, reads it or receives something produced from it.
- Every other file, report or system that links to it.
- The calculations and rules people rely on, with a few worked examples.
- A decision on how much history to migrate, and what happens to the old file.
- Who owns the data model, the picklists and the reports after launch.
- The cutover approach, the freeze window and the go or no-go check.
Our experience includes database design and optimization on SQL Server, PostgreSQL and MySQL, VBA and Visual Basic, and full-stack web applications in React, Next.js, TypeScript and Node.js. See web application development for what we build, and the sample handover package for the documentation and runbooks your team would receive.
Sources
- Access specifications (Microsoft)
- Excel specifications and limits (Microsoft)
See it applied
Share this guide
Related services
- Web application development Portals, dashboards and internal tools built with React, Next.js and TypeScript.
- Custom software development Internal tools and integrations built to work with the systems you already run.
- AWS cloud & DevOps Hosting, deployment pipelines and monitoring for the apps we build.
Topics