Most ERP deployments don’t fail because the software is bad. They fail because someone skipped a step they assumed was obvious, and nobody caught it until a client was staring at broken invoices on day one.
I’ve seen it enough times. The demo environment looks great. The staging tests pass. Everyone signs off. Then production hits and something is wrong with permissions, or a module dependency wasn’t installed in the right order, or the database schema drifted between environments because migrations weren’t handled cleanly. This post is the checklist I wish I’d had earlier. It’s not exhaustive for every possible ERP stack, but it covers the things that actually bite people.
Start With Your Environment Configuration
Before anything else, your environment config needs to match what production actually looks like. This sounds obvious. It’s not always done.
Confirm Environment Variables Are Complete
The number of times a .env file from staging makes it into production with the wrong values is genuinely alarming. Go through every environment variable deliberately:
- Database connection strings (host, port, user, password, database name)
- Secret keys and tokens (make sure these are production values, not the dev defaults)
- Email service configuration
- File storage paths or cloud storage credentials
- Feature flags if your platform supports them
Don’t copy the staging file and assume you just need to change the database URL. Read every line.
Verify Your Async Workers Are Configured for Load
If your ERP runs async operations (and it should, for the reasons covered in Async Python in ERP: Why Blocking I/O Is Killing Your Throughput), make sure your worker counts are set for production traffic, not development convenience. A single worker that handles background jobs in dev will buckle immediately under real load.
Check Logging Levels
Debug logging that’s fine in staging will fill up disk in production within days on a busy system. Set log levels appropriately and confirm your log rotation policy is in place before you flip the switch.
Verify Module Installation Order and Dependencies
Modular ERP systems give you flexibility. They also give you dependency trees that can cause weird failures if you’re not careful.
Install Foundation Modules First
Some modules assume others are already present. Core functionality like authentication, user management, and base configuration need to be installed before anything that depends on them. Don’t assume the installer handles this automatically without checking.
Audit Which Modules Are Actually Needed
This one gets overlooked under deployment pressure. You’ve been building and testing for weeks, and somewhere along the way, someone installed a module to test something and never removed it. ERP Module Installation: What to Actually Think About Before You Add Another Module covers this in detail, but the short version is: every module you don’t need is surface area for bugs and performance overhead. Do a final audit before go-live.
Confirm Module Versions Are Consistent
If you’re deploying an open core system where some modules come from the community or are custom-built, version mismatches are a real problem. A module built against an older version of the core might work fine most of the time and then silently fail on an edge case.
Validate Your Database State
Schema issues discovered after go-live are the worst kind of issues. They’re often subtle, they affect data integrity, and fixing them under pressure usually makes things worse.
Confirm Schema Is in the Expected State
If your platform handles schema changes automatically (like Fullfinity does, which is the whole point of Zero Migration Files: How Fullfinity Handles Schema Changes Automatically), you still need to verify that the auto-management ran correctly against your production database. Connect to the database directly and spot-check the tables and columns you expect to exist.
Check Indexes Are Created
Automatic schema management doesn’t always mean optimal schema management. Indexes that exist in your dev environment might not exist in production if they were added manually rather than through the ORM definition. Query performance in production can look nothing like staging if your indexes are missing.
Validate Foreign Key Constraints
Especially if you migrated data from a legacy system or imported seed data, foreign key constraints can be violated in ways that don’t surface until a user tries to delete or update a record. Run integrity checks before users touch the system.
Seed Data and Fixtures Are Loaded
This is surprisingly easy to forget. Your application might depend on certain base records existing: default roles, tax configurations, country/currency data, status types. If those aren’t present, users hit errors that look random but have a clear cause. Make sure all required fixtures ran successfully.
Permissions and Access Control
Permissions are the thing that looks fine until it doesn’t. And when it breaks in production, it breaks in front of real users.
Map Every Role to the Right Access Level
Don’t test permissions just as an admin. Log in as each role type that will actually be used on day one. Check that users can access what they should, and can’t access what they shouldn’t. This is tedious and worth doing anyway.
Verify Field-Level Access Where It Matters
Some ERP operations involve sensitive fields: pricing, cost data, employee compensation, banking details. If your ORM supports access-aware field loading, confirm that the access rules are actually working as intended, not just theoretically configured. The Access-Aware ORM: Why Your ERP’s Database Layer Is Probably Doing Too Much Work post gets into why this matters at the query level too.
Confirm API Token Scopes
If external systems are connecting via API, make sure those tokens have the minimum necessary scope. Don’t let a read-only integration token have write access because it was convenient during testing.
Audit Admin Accounts
Before go-live, remove any test admin accounts. Change default passwords. If your team created a shared credentials account for testing, lock it down or delete it. This is basic but frequently skipped.
Data Migration Validation
If you’re migrating from a legacy system, this section matters more than almost anything else. Bad data in production is a crisis.
Row Count Validation
Compare record counts between your source system and destination for every major entity: customers, products, invoices, orders, contacts. Even small discrepancies need to be explained before you go live, not after.
Spot Check Critical Records
Pick 20-30 specific records that people actually know well (the company’s biggest customers, recent invoices, active orders) and manually verify them. Automated validation catches structural problems. Manual spot checks catch the semantic ones that scripts miss.
Validate Numeric Fields
Financial data especially. Totals, balances, tax amounts, currency conversions. A migration script that handles most cases correctly can still have an off-by-one error or a rounding issue that compounds over thousands of records.
Check Date and Timezone Handling
Date fields are deceptively dangerous. A migration that runs in one timezone on a server configured for another will shift dates. This affects everything from invoice due dates to subscription renewal dates to payroll periods. Test explicitly across timezone boundaries.
Performance and Load Validation
Your staging environment is never exactly like production. You need at minimum a basic sanity check on performance before real users arrive.
Test With Realistic Data Volume
Staging databases are often small. If production has 500,000 product records and staging has 500, your query performance numbers are meaningless. Before go-live, either populate staging with representative volume or run targeted load tests against production before the official launch.
Check Slow Query Logs
Run a representative set of typical user workflows and check the slow query log. Anything over a threshold you’re comfortable with needs investigation. Don’t assume it’ll be fine. It won’t.
Verify Connection Pool Settings
Database connection pools that are sized for a small dev team won’t hold up when multiple departments start using the system simultaneously. Check your pool size, timeout settings, and max connection limits against what the database server is actually configured to allow.
Test Background Job Queue Under Load
If your ERP processes things asynchronously in the background (report generation, email sending, inventory updates, etc.), make sure the job queue doesn’t fall over when multiple jobs are queued at once. Background job failures often don’t surface until someone notices a report hasn’t arrived or an email wasn’t sent.
Integration Readiness
Most ERP deployments don’t live in isolation. There are integrations that have to work from day one.
Verify Webhook Endpoints Are Reachable
If external systems are expecting webhooks from your ERP, confirm those endpoints are reachable from your production network. Firewalls and network policies that weren’t an issue in staging can silently drop outbound connections in production.
Test Each Integration End-to-End
Don’t just confirm that the integration is configured. Actually fire a test transaction and verify it shows up correctly on both ends. An integration that’s connected but not working is worse than one that’s obviously broken, because it creates data inconsistencies you might not notice for days.
Confirm Rate Limits on External APIs
If your ERP calls external services (payment processors, shipping APIs, tax services), check the rate limits on those services against your expected transaction volume. You can be well within limits during staging and blow past them in production on a busy day.
Final Pre-Launch Checks
These are the things you do in the last hour before users show up.
Backup the production database. Right now, before any go-live activity. If something goes catastrophically wrong in the first hour, you need a clean restore point.
Confirm your rollback plan. Know exactly what steps you’d take to roll back to the previous system if something breaks badly. Write it down. Don’t improvise this under pressure.
Verify monitoring and alerting is active. Error tracking, uptime monitoring, and any performance dashboards should be configured and actually sending alerts to the right people. Find out production is down from your monitoring system, not from a client email.
Check SSL certificates. Expiry dates, correct domain coverage, HSTS headers if relevant. A cert that expires two days after go-live is a bad way to start.
Confirm backup schedules are running. A database backup taken manually before go-live is not the same as an automated backup schedule that will protect you going forward. Make sure scheduled backups are configured and confirmed working.
Do a final UAT sign-off with stakeholders. Not your team. The actual people who will use the system. Walk through their core workflows one more time with them. Their definition of “working correctly” is sometimes different from yours.
Conclusion
The checklist above won’t cover every possible edge case for every deployment. But it covers the categories where real problems actually happen: environment config, module dependencies, database state, permissions, data integrity, performance, and integrations.
The three things that matter most:
- Don’t skip the permissions audit. It’s tedious and it’s the thing that causes the most visible, trust-damaging failures in the first week.
- Validate data integrity before users touch anything. A corrupted or incomplete migration is much harder to fix after users have been adding records on top of it.
- Know your rollback plan before you need it. The worst time to figure out how to roll back is when something is actively broken and people are waiting.
If you’re building on Fullfinity, a lot of the infrastructure concerns (schema management, async performance, module dependencies) are handled at the platform level. But deployment is still deployment. The checklist still applies.
Explore how Fullfinity handles the underlying complexity at /, or browse more technical guides on /blog.