---
title: Local Development for a Microservices Travel Platform
description: "How our engineers run the entire AI travel booking stack on their laptops — local orchestration, database seeding, mock services, and fast feedback loops."
canonical: https://nowah.xyz/blog/local-development-microservices
lastModified: "2026-08-07T03:53:01.438Z"
---

# Local Development for a Microservices Travel Platform

How our engineers run the entire AI travel booking stack on their laptops — local orchestration, database seeding, mock services, and fast feedback loops.

"It works on my machine" is not acceptable when your machine books real flights. The gap between a developer's local environment and production is where bugs hide, and in a travel booking platform, those bugs can charge credit cards and reserve airline seats.

Our local development setup prioritizes two things: parity with production (so bugs found locally are the same bugs that would appear in production) and developer speed (so the [feedback loop](/blog/feedback-loop-post-trip-data-improves-ai) between code change and visible result is seconds, not minutes).

## Starting the local stack

![Illustration for this section](https://pics.nowah.xyz/website-media/infrastructure-049-img-1.webp)

A developer's local environment runs the API server, a database, and a cache\. The API server starts with \`npm run dev\` on port 3000\. Hot reload is enabled, so code changes take effect in seconds without restarting the server\.

The database runs locally, either as a native installation or in a container\. The schema is applied with a schema\-sync command, which reads the schema definition file and makes the database match it\. The type\-safe client is regenerated with \`npx prisma generate\`\. These two commands bring the local database to the same schema state as production\.

The cache runs locally as well. Same version as production. The local instance is much smaller (no replication, minimal memory), but the data structures and access patterns are identical.

## Seeding with realistic data

An empty database is useless for development. You can't test flight search without airport data. You can't test airline display without airline data. You can't test trip views without trip records.

We provide seeding scripts: \`npm run sync:airports\` populates the airport reference data \(thousands of airports with codes, names, locations\)\. \`npm run sync:airlines\` populates airline data\. These scripts pull from the same source as production, so the reference data matches exactly\.

For user and trip data, developers create test accounts and test trips as needed. We provide a seed script that creates common scenarios: a user with no trips, a user with one upcoming trip, a user with multiple trips in different states. This covers the common development cases without requiring manual data setup.

The visual database browser (a local database browser) lets developers inspect and modify data directly. When debugging a query that returns unexpected results, being able to look at the actual database rows is invaluable.

## Mock services for external dependencies

![Supporting diagram](https://pics.nowah.xyz/website-media/infrastructure-049-img-2.webp)

Our platform depends on external services: a travel data provider for flight and hotel search, a payment processor for transactions, an identity provider for authentication, and others.

For local development, we use sandbox and test modes of these services. The payment processor's test mode accepts test card numbers and simulates various scenarios (successful payment, declined card, 3D Secure challenge) without processing real transactions.

The travel data provider offers a test environment that returns real flight data from their sandbox. The searches are real (actual routes, actual airlines), but any bookings created are test bookings that don't reserve real seats.

For the identity provider, we use their development instance with test credentials. Authentication flows work identically to production, just against a separate user database.

When [external APIs](/blog/circuit-breakers-external-apis) are unavailable (offline development, rate limit exceeded on the sandbox), developers can run with mock responses. A mock middleware intercepts external API calls and returns canned responses. This is less realistic but allows development to continue without external dependencies.

## Fast feedback loops

The development server watches for file changes and reloads automatically. A code change to an API endpoint is testable within seconds: save the file, the server reloads, send a request. No build step. No container restart.

For frontend development, the same applies. The the mobile build tooling development server for the mobile app supports hot reload. A style change appears on the simulator in under a second. A logic change takes a few seconds.

The feedback loop matters enormously for productivity. If a developer has to wait 30 seconds after every change to see the result, they make fewer changes and take longer to iterate. Sub-second feedback means the developer can experiment freely, which leads to better code.

## Debugging across services

When something goes wrong in the local stack, the developer needs to trace the issue [across services](/blog/tracing-booking-across-services). A request that starts in the mobile app, hits the API server, calls an external service, and enqueues a background job spans multiple boundaries.

[Structured logging](/blog/structured-logging-first-investment) helps here. The correlation ID that we use in production also works locally. A request's correlation ID appears in every log entry, so the developer can follow a request from the mobile app's network tab through the API server's console output to the worker's job processing log.

For interactive debugging, the developer can attach a debugger to the API server process. Breakpoints in tool call handlers, booking logic, or [payment processing](/blog/launching-payment-processing-ai-handles-money) let them step through the code while the mobile simulator waits for the response. The streaming architecture means the simulator shows progress indicators while the developer is paused at a breakpoint.

## Setting up your own local dev environment

If you're building a [microservices platform](/blog/microservices-travel-platform-worth-it), here's what makes local development work.

Single command startup\. \`npm run dev\` should start everything the developer needs\. If starting the local environment requires five terminal windows and a page of instructions, developers will avoid restarting it, which means they'll develop against stale state\.

Seed data that covers common scenarios. Don't make developers create test data from scratch. Provide scripts that set up a realistic baseline.

Use sandbox APIs for external dependencies. Mock only when sandbox is unavailable. Real APIs (even in sandbox mode) catch integration issues that mocks hide.

Prioritize hot reload. Every second of rebuild time is a productivity tax. Invest in fast reloads early. The compound effect over months of development is significant.

Match production schema. The local database schema should be managed by the same tooling as production. A drift between local and production schema is a bug waiting to happen.

---

Nowah is an AI travel agent that searches and books real flights and hotels through conversation — no filters, no thirty open tabs. [Plan your next trip](https://app.nowah.xyz).
