A ServiceNow backend service manages critical customer data. How would you design a robust database migration strategy to introduce schema changes without downtime or data loss?

ServiceNowBackend Developer3–5 YearsDatabases

The core of a robust database migration strategy for a critical backend service, especially when aiming for zero downtime and data loss, revolves around careful planning, incremental changes, and a strong rollback plan. This typically involves using an evolutionary database design approach, where schema changes are applied in small, non-disruptive steps. Key considerations include schema versioning tools, application-level compatibility, and a phased deployment. For complex changes, techniques like the expand/contract pattern are crucial, allowing both old and new application versions to operate concurrently against a transitional schema.

Implementing a zero-downtime migration

For significant schema changes, the expand/contract pattern is the most reliable. This involves an “expand” phase where new columns or tables are added, and data is optionally backfilled or duplicated, but old application versions still use the original schema. The next step is to update the application to use the new schema, potentially reading from both for a transition period. Finally, in the “contract” phase, after verifying stability, the old columns or tables are removed. This ensures no breaking changes occur for any active application version at any point.

Best practice

Always use an automated database migration tool (e.g., Flyway, Liquibase, Alembic) to manage schema versions. These tools track applied migrations, enforce ordering, and allow for repeatable deployments across environments. Integrating these migrations into your CI/CD pipeline ensures that schema changes are tested and deployed consistently, reducing human error and facilitating faster, safer releases. They also provide mechanisms for generating rollback scripts, though proactive planning to avoid rollbacks is always preferred.

Edge case interviewers probe for

Interviewers often ask about handling large data volumes during migrations, specifically when adding a new non-nullable column or modifying an existing one on a table with millions of rows. Directly adding a non-nullable column without a default value will cause downtime. The solution involves adding the column as nullable first, backfilling data in batches, then adding a default, and finally making it non-nullable. Alternatively, for large tables, creating a new table with the desired schema, migrating data, and then performing a table swap or rename can be less disruptive, depending on the database system.

Common mistake

A common mistake is directly modifying or dropping columns that are actively used by the current production application without a phased approach. This leads to immediate application errors or data loss. Another error is neglecting to test the migration thoroughly in a production-like environment with realistic data volumes, which can expose performance issues or unexpected failures only during the actual deployment. Always test the migration script itself, not just the resulting schema.

What the interviewer is checking

The interviewer is assessing your understanding of database evolution principles, your ability to think critically about maintaining data integrity and system availability under change, and your familiarity with practical tools and patterns for managing schema migrations in a high-stakes production environment. They want to see if you can design strategies that minimize risk and impact to end-users.

Imagine you have a big library where all the books (your data) are organized on shelves (your database schema). You want to reorganize some shelves, maybe add a new section for graphic novels or change how you categorize biographies, but you can’t close the library because people are always checking out and returning books.

To do this without stopping service, you’d slowly introduce the new organization. First, you might add empty new shelves next to the old ones. People still use the old shelves. Then, you hire an assistant (your new application version) who knows about both the old and new ways. Gradually, new books go onto the new shelves, and existing books are moved over during quiet times. Only once everyone is using the new shelves and you’re sure no one needs the old system, you remove the old shelves.

Why interviewers ask this

Interviewers ask this to gauge your experience with critical system maintenance, your understanding of data integrity, and your ability to plan for high availability. It tests your practical knowledge beyond just writing SQL.

What a strong answer signals

A strong answer demonstrates a methodical approach, familiarity with industry best practices like schema versioning and the expand/contract pattern, and an awareness of potential pitfalls and how to mitigate them. It signals you are a reliable engineer for production systems.

Common follow-ups

  • How do you handle rollbacks for failed migrations?
  • What monitoring would you put in place during and after a migration?
  • How would your strategy change for a sharded database?

Advanced variation

Design a database migration strategy for a multi-tenant SaaS platform where each tenant has their own isolated schema, and you need to roll out a major schema upgrade across all tenants with varying update cadences and strict SLAs.

Consider a scenario where a core orders table needs a new discount_code column, which must eventually be non-nullable. Instead of adding it directly, the strategy would involve: 1. Adding discount_code as a nullable column. 2. Deploying an application update that writes to this new column while still being compatible with old reads. 3. Running a background job to backfill existing orders with a default N/A or null discount code. 4. Once backfill is complete and verified, deploying another migration to make the column non-nullable. This phased approach allows the application to remain fully operational throughout.

schema_migrations.sql
-- Migration 1: Add new column as nullable
ALTER TABLE orders
ADD COLUMN discount_code VARCHAR(50) NULL;

-- Deploy app version 1.1 (reads from and writes to discount_code, handles nulls)
-- Run backfill script for existing data
-- e.g., UPDATE orders SET discount_code = 'N/A' WHERE discount_code IS NULL;

-- Migration 2: Make column non-nullable with a default (after backfill)
-- This assumes a default value is appropriate after initial backfill.
-- If not, the application must ensure no nulls are inserted going forward.
ALTER TABLE orders
ALTER COLUMN discount_code VARCHAR(50) NOT NULL DEFAULT 'NONE';

-- Deploy app version 1.2 (can assume discount_code is never null)

-- Alternative for very large tables if immediate NOT NULL is required after backfill:
-- 1. Create a new table with the desired schema.
-- CREATE TABLE orders_new (...)
-- 2. Copy/migrate data from orders to orders_new (potentially in batches).
-- 3. Rename tables (e.g., RENAME TABLE orders TO orders_old, orders_new TO orders).
-- This typically requires a brief application downtime or sophisticated database features.
Old App Old Schema 1. Expand Old App Dual Schema 2. App Update New App Dual Schema 3. Contract New App New Schema
  1. 1Plan database migrations meticulously to avoid downtime and data loss in production.
  2. 2Utilize automated schema migration tools to ensure version control and repeatable deployments.
  3. 3Employ the expand/contract pattern for complex changes to allow concurrent operation of old and new application versions.
  4. 4Thoroughly test migration scripts in production-like environments with realistic data volumes.
  5. 5Address large table modifications by adding nullable columns first, backfilling, then making them non-nullable.