Skip to main content

Setup Guide

This guide details the steps required to set up and run the application using Docker. Docker handles all dependencies including PostgreSQL, Bun, and Next.js (the application itself).

Setup Instructions

1. Start the Application

tip

For faster start time, the --build option should only be used for the first time running the application, not using it will make the app depend on cache.

# Delete cache (.next and node_modules, not database)
sudo rm -r ./.docker-cache

Development Mode

# Start services
docker-compose -f docker-compose.yml -f docker-compose.dev.yml up --build -d

Production Mode

# Start services
docker-compose up --build -d

Runtime commands

# Host Prisma studio
docker-compose exec app bun prisma:studio
# Stop services
docker-compose down
# View logs
docker-compose logs -f

Note: The first startup will take longer as it builds the Next.js application and runs database migrations.

2. Initialize the Database Schema

The database schema is automatically initialized when you start the application. The Docker entrypoint script runs:

  1. prisma generate - Generates the Prisma client
  2. prisma migrate deploy - Applies all migrations
  3. Builds and starts the application

3. Add Full-Text Search Functionality

danger

The application's search feature relies on advanced PostgreSQL functions that cannot be automatically generated by Prisma. You must manually execute custom SQL.

Execute the following commands:

# Access the PostgreSQL container
docker-compose exec db psql -U myuser -d mydb

Replace myuser and mydb with the values from your .env file.

Then run this SQL inside the psql terminal:

-- STEP 1: DEFINE THE UPDATE FUNCTION
-- This function will be called by the trigger automatically.
-- We use 'setweight' to give matches in 'name' a higher priority ('A')
-- than matches in 'slug' ('B'). This can be used later to rank search results.
CREATE OR REPLACE FUNCTION update_product_search_vector()
RETURNS TRIGGER AS $$
BEGIN
NEW.search_vector :=
setweight(to_tsvector('simple', coalesce(NEW.name, '')), 'A') ||
setweight(to_tsvector('simple', coalesce(NEW.slug, '')), 'B');
RETURN NEW;
END;
$$ LANGUAGE plpgsql;

-- STEP 2: CREATE THE TRIGGER
-- This trigger ensures the function runs automatically whenever a product is created or updated.
-- We drop the old one first to avoid errors.
DROP TRIGGER IF EXISTS tsvector_update ON "Product";
CREATE TRIGGER tsvector_update
BEFORE INSERT OR UPDATE ON "Product"
FOR EACH ROW
EXECUTE FUNCTION update_product_search_vector();

-- STEP 3: BACKFILL EXISTING DATA (ONE-TIME)
-- This updates all existing products in your table to have a search_vector.
-- It's crucial for making old products searchable.
UPDATE "Product"
SET search_vector = (
setweight(to_tsvector('simple', coalesce(name, '')), 'A') ||
setweight(to_tsvector('simple', coalesce(slug, '')), 'B')
)
WHERE search_vector IS NULL; -- Only update rows that haven't been processed

-- STEP 4: CREATE THE PERFORMANCE INDEX
-- This GIN index is what makes the full-text search fast.
-- Without it, searches will be very slow on a large table.
CREATE INDEX IF NOT EXISTS "Product_search_vector_idx" ON "Product" USING GIN(search_vector);

Type \q to exit the psql terminal.

4. Syncing Manual SQL with Prisma Migrations (For Feature Updates)

After applying the manual SQL for full-text search, you must update Prisma's migration history to prevent errors with future migrations. This process informs Prisma that the manual changes are now part of the official migration history.

Follow these steps:

Step 1: Create an empty migration file

Since the database changes already exist (from the manual SQL above), we create a migration that represents those changes but won't actually execute anything:

docker-compose exec app sh -c 'MIGRATION_NAME=$(date +%Y%m%d%H%M%S)_add_full_text_search && mkdir -p prisma/migrations/$MIGRATION_NAME && echo "-- This migration is empty because the changes already exist in the database" > prisma/migrations/$MIGRATION_NAME/migration.sql && echo $MIGRATION_NAME'

This will output the migration name (e.g., 20251224084447_add_full_text_search). Copy this name for the next step.

Step 2: Check migration status

Verify that Prisma recognizes the new migration:

docker-compose exec app bunx prisma migrate status

You should see the migration you just created listed as "not yet been applied".

Step 3: Mark the migration as applied

Tell Prisma that this migration has already been applied to the database. Replace MIGRATION_NAME_HERE with the name from Step 1:

docker-compose exec app bunx prisma migrate resolve --applied MIGRATION_NAME_HERE

Example:

docker-compose exec app bunx prisma migrate resolve --applied 20251224084447_add_full_text_search

Step 4: Verify everything is in sync

Confirm that there are no pending migrations and no drift:

docker-compose exec app bunx prisma migrate status

You should see a message like "Database schema is up to date!"


5. Updating Schema Without Losing Data (Development Workflow)

When you need to update the Prisma schema during development and already have data in your database:

For development when you have manual SQL that Prisma can't track, use db push instead of migrations:

# Make your schema changes in schema.prisma, then:
docker-compose exec app bunx prisma db push

# Regenerate Prisma client
docker-compose exec app bunx prisma generate

# Restart your dev server

What db push does:

  • Applies schema changes directly to the database
  • Skips the migration system entirely
  • Won't complain about drift
  • Won't lose your data
  • Perfect for development iteration

Alternative: Create Migrations Despite Drift (Advanced)

If you need proper migrations for production deployment:

Step 1: Create the migration file without applying it:

docker-compose exec app bunx prisma migrate dev --name your_change_name --create-only

You'll see the drift warning - ignore it and let it create the migration anyway by pressing y if prompted, or it will exit with an error.

Step 2: If it exits with error, manually create the migration:

docker-compose exec app bunx prisma migrate dev --name your_change_name --create-only --skip-seed

Step 3: Inspect the generated migration file:

# View the latest migration
docker-compose exec app cat prisma/migrations/$(ls -t prisma/migrations | head -1)/migration.sql

Verify it contains your actual schema changes (like ALTER TABLE statements), not just a comment.

Step 4: Apply the migration:

docker-compose exec app bunx prisma migrate deploy

Step 5: Regenerate Prisma client:

docker-compose exec app bunx prisma generate

Important Notes

danger

Empty Drift Resolution Migrations Don't Apply Schema Changes

When you create a migration just to resolve drift (like 20251224085842_resolve_drift), it only contains a comment and doesn't actually modify your database. After resolving drift, you must still apply your schema changes using either:

  • prisma db push (recommended for development)
  • A new proper migration (for production)
warning

Common Mistake: Forgetting to Apply Changes After Resolving Drift

  1. Wrong: Resolve drift → assume changes are applied → wonder why fields are missing
  2. Correct: Resolve drift → run db push or create new migration → changes are applied

Remember: Drift resolution only syncs migration history. Your schema changes still need to be applied separately!

tip

Development vs Production Strategy

  • Development: Use prisma db push for quick iteration without migration files
  • Production: Use proper migrations with prisma migrate deploy
  • When to switch: Before deploying to production, create a proper migration that captures all your development changes

If you encounter drift errors when resolving drift:

Only follow this if you see drift when trying to sync migration history (not when making schema changes):

Step 1: Create an empty migration for the drift:

docker-compose exec app sh -c 'MIGRATION_NAME=$(date +%Y%m%d%H%M%S)_resolve_drift && mkdir -p prisma/migrations/$MIGRATION_NAME && echo "-- Resolving schema drift" > prisma/migrations/$MIGRATION_NAME/migration.sql && echo "Created migration: $MIGRATION_NAME"'

This will output the migration name. Copy this name for Step 3.

Step 2: Check what migration was created:

docker-compose exec app bunx prisma migrate status

You should see your new migration listed as "not yet been applied".

Step 3: Mark it as applied. Replace MIGRATION_NAME_HERE with the name from Step 1:

docker-compose exec app bunx prisma migrate resolve --applied MIGRATION_NAME_HERE

Example:

docker-compose exec app bunx prisma migrate resolve --applied 20251224085751_resolve_drift

Step 4: Verify the drift is resolved:

docker-compose exec app bunx prisma migrate status

You should see "Database schema is up to date!"

Step 5: Now apply your actual schema changes:

docker-compose exec app bunx prisma db push
docker-compose exec app bunx prisma generate

Useful Docker Commands

# View real-time logs
docker-compose logs -f

# View logs for a specific service
docker-compose logs -f app
docker-compose logs -f db

# Show existing logs and exit
docker-compose logs

# Restart services
docker-compose restart

# Stop and remove all containers, networks, and volumes
docker-compose down -v

# Rebuild without cache
docker-compose build --no-cache

# Access the app container shell
docker-compose exec app sh

# Access the database container
docker-compose exec db psql -U myuser -d mydb

# In-case the app didn't recognize the DB tables at first launch
docker compose exec app bunx dotenv -e .env.local -- bunx prisma db push --force-reset

# In-case the app didn't recognize the whole DB migrations and failed to start at first launch
docker compose run --entrypoint /bin/sh --rm app -c "bunx prisma migrate reset --force"

Troubleshooting

Database connection errors

  • Ensure the .env file uses db as the host (not localhost)
  • Check that all services are running: docker-compose ps
  • View logs: docker-compose logs db

Port already in use

If ports 3000 or 5432 are already in use:

  • Stop the conflicting service
  • Or modify the ports in docker-compose.yml

Changes not reflecting

  • For code changes in dev mode: They should auto-reload
  • For Docker/environment changes: Run docker-compose up --build

Last updated on January 30, 2026 by Ayman.