> ## Documentation Index
> Fetch the complete documentation index at: https://docs.opnform.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Docker Development Setup

> Set up OpnForm locally for development using Docker

<Note>
  The easiest way to get started with OpnForm is through our [official managed service in the Cloud](https://opnform.com/?utm_source=docs\&utm_medium=introduction\&utm_campaign=cloud_version). It takes just 1 minute to start building forms with the free plan, with high availability, backups, security, and maintenance all managed for you.
</Note>

## Overview

OpnForm provides a minimal Docker-based development environment optimized for local development. While the full architecture is detailed in our [Docker Deployment](/deployment/docker) guide, the development setup is intentionally lighter and focused on developer experience.

## Prerequisites

* Docker and Docker Compose installed on your machine
* Git installed
* Basic understanding of Docker concepts

## Quick Start

1. Clone the repository:

   ```bash theme={null}
   git clone https://github.com/OpnForm/OpnForm.git
   cd OpnForm
   ```

2. Run the setup script in development mode:

   ```bash theme={null}
   chmod +x scripts/docker-setup.sh
   ./scripts/docker-setup.sh --dev
   ```

   This script will:

   * Pull or build required Docker images
   * Start all containers in development mode with embedded configuration
   * Display access information

   <Note>
     Development mode doesn't require .env files - all configuration is
     embedded in docker-compose.dev.yml for simplicity. This includes
     `JWT_SKIP_IP_UA_VALIDATION=true`, which disables JWT User Agent checks
     for easier local testing. Production Docker deployments should keep this
     setting disabled.
   </Note>

3. Access your development environment:
   * **Frontend**: [http://localhost:3000](http://localhost:3000) (direct access to Nuxt dev server)
   * **API**: [http://localhost/api](http://localhost/api) (proxied through nginx)

### Initial Setup

After starting the development environment, OpnForm will automatically redirect you to a setup page where you can create your admin account. Simply visit `http://localhost:3000/setup` and you'll be guided through the setup process.

<Note>
  Public registration is disabled in the self-hosted version after setup is
  complete. Use the admin account to invite additional users. Free
  self-hosted instances are limited to 2 users total across the instance;
  activate a self-hosted Enterprise license to add more users.
</Note>

## Architecture

The development setup is intentionally simplified compared to our [Docker Deployment](/deployment/docker) production setup, with a focus on developer experience and faster iteration.

## Codex worktrees

When you create an OpnForm worktree in Codex, Codex uses the repository environment in `.codex/environments` to prepare an isolated local stack automatically. This workflow does not use the shared development containers from `docker-compose.dev.yml`.

The worktree receives its own PostgreSQL Docker volume, API port, and Nuxt port. Laravel and Nuxt run from the current checkout, so the browser always reflects that worktree's files.

Use the Codex actions when available:

* **Start app** starts the database, API, and Nuxt server.
* **Reset DB** runs migrations and `Database\\Seeders\\E2ETestSeeder` only for the current worktree.
* **Stop app** stops Laravel and Nuxt while preserving the local database for a fast restart.
* **Run E2E** resets the worktree database and runs Playwright against its local URLs.

The scripts are also available from the repository root:

```bash theme={null}
./scripts/codex-worktree-setup.sh
./scripts/codex-worktree-up.sh
```

The startup output contains the exact UI URL. Opening its root URL automatically signs in the local Codex admin (`e2e@example.test` / `Abcd@1234`). The reset seed creates three sample forms and five completed submissions across two public forms.

<Warning>
  Do not run `docker compose -f docker-compose.dev.yml up` for concurrent Codex worktrees. That stack has shared container names and fixed host ports. Use the Codex worktree actions instead.
</Warning>

### Key Simplifications

* **No .env Files**: All configuration embedded in docker-compose.dev.yml - no environment file generation needed
* **Direct Frontend Access**: Frontend runs on port 3000 with direct access, bypassing nginx proxy
* **Lightweight nginx**: Only handles API routes and Laravel backend, eliminating redundant frontend proxying
* **Simplified networking**: Fewer moving parts, cleaner logs, easier debugging

### Differences from Production

* **No Redis**: Uses file-based caching and sessions instead

  * Simpler setup
  * No additional service to maintain
  * Slightly slower but sufficient for development

* **No Queue Workers**: Uses synchronous job processing

  * Jobs run immediately in the main process
  * Easier debugging of background tasks
  * No need to restart workers after code changes

* **No Scheduler**: Scheduled tasks don't run automatically

  * Run scheduled tasks manually when needed
  * Less resource usage
  * Cleaner logs

* **Embedded Configuration**: No `.env` files needed

  * All variables set directly in docker-compose.dev.yml
  * Includes secure development keys (APP\_KEY, JWT\_SECRET)
  * Pre-configured mail settings using log driver
  * Immediate startup without setup scripts

### Development Features

The development setup includes:

#### Frontend Development

* **Hot Module Replacement (HMR)**: Changes to Vue components and styles are instantly reflected without page reload
* **Vue DevTools**: Full integration for component inspection and state management debugging ([learn more](https://devtools.vuejs.org/))
* **Source Maps**: Enabled for easier debugging
* **Fast Refresh**: Preserves component state during updates
* **Error Overlay**: Displays errors directly in the browser

#### Backend Development

* **PHP Hot Reload**: Changes to PHP files are immediately available
* **Xdebug Integration**: Ready for step-by-step debugging
* **Artisan Commands**: Direct access to Laravel's CLI tools

#### Performance Optimizations

The development setup includes smart optimizations for faster iteration:

* **Smart Dependency Install**: Automatically detects when `package.json` has changed and only reinstalls when necessary
  * First startup: Full npm install (2-3 minutes)
  * Subsequent startups: "Dependencies up to date, skipping install" (5 seconds)
  * Automatic detection when dependencies change
* **Persistent Node Modules**: Dependencies stored in Docker volumes to avoid reinstallation
* **Fast Container Restarts**: Skip dependency installation on container restart

### Development URLs

* **Frontend**: [http://localhost:3000](http://localhost:3000)

  * Direct access to Nuxt dev server with HMR
  * Vue DevTools available
  * All client-side routing handled directly

* **API**: [http://localhost/api](http://localhost/api)
  * Lightweight nginx proxy to Laravel API
  * Routes all backend requests through Laravel's front controller
  * PHP-FPM processing for server-side logic
  * Supports file uploads and long requests

<Note>
  In development, nginx handles all Laravel routes (including `/`, `/api/*`,
  `/forms/*`) through the standard Laravel front controller pattern. The
  frontend is accessed directly on port 3000, eliminating redundant proxying.
</Note>

## File Structure

The development setup mounts your local directories into the containers:

```
OpnForm/
├── api/                    # Laravel API (mounted to api container)
│   ├── vendor/            # Preserved in container
│   └── storage/           # Mounted for logs and uploads
├── client/                # Nuxt frontend (mounted to ui container)
│   └── node_modules/      # Preserved in container
└── docker/                # Docker configuration files
```

## Common Tasks

### Running Commands

To run commands in the containers:

```bash theme={null}
# Laravel Artisan commands
docker compose -f docker-compose.dev.yml exec api php artisan [command]

# NPM commands
docker compose -f docker-compose.dev.yml exec ui npm [command]

# Database commands
docker compose -f docker-compose.dev.yml exec db psql -U forge
```

### Accessing Logs

View container logs:

```bash theme={null}
# All containers
docker compose -f docker-compose.dev.yml logs -f

# Specific container (e.g., frontend)
docker compose -f docker-compose.dev.yml logs -f ui
```

### Database Access

The PostgreSQL database is accessible:

* From containers: `host=db`
* From your machine: `localhost:5432`
* Default credentials:
  ```
  Host: localhost
  Port: 5432
  Database: forge
  Username: forge
  Password: forge
  ```

## Troubleshooting

### Container Issues

If containers aren't starting properly:

```bash theme={null}
# Clean everything and restart
./scripts/docker-setup.sh --dev
```

### Frontend Access Issues

If you get **503 errors** when accessing the frontend:

<Steps>
  <Step title="Use IPv4 address">
    Always use `http://127.0.0.1:3000` instead of `http://localhost:3000`

    <Warning>
      `localhost` can resolve to IPv6 (`::1`) on some systems, causing connection issues with Docker's port binding.
    </Warning>
  </Step>

  <Step title="Check container logs">
    Verify the Nuxt dev server started successfully: `bash docker compose -f
            docker-compose.dev.yml logs ui ` Look for: `"Dependencies up to date,
            skipping install"` and `"➜ Local: http://0.0.0.0:3000/"`
  </Step>

  <Step title="Restart containers if needed">
    ```bash theme={null}
    docker compose -f docker-compose.dev.yml restart ui
    ```
  </Step>
</Steps>

### Environment Variables

Development mode uses embedded configuration - no `.env` files needed:

* **APP\_KEY** and **JWT\_SECRET**: Pre-configured development keys
* **Database**: Defaults to `forge/forge` credentials
* **Mail**: Uses log driver for development
* **Storage**: Local filesystem with public visibility

To customize variables, edit them directly in `docker-compose.dev.yml`.

### Permission Issues

If you encounter permission issues:

```bash theme={null}
# Fix storage permissions
docker compose -f docker-compose.dev.yml exec api chmod -R 775 storage

# Fix vendor permissions
docker compose -f docker-compose.dev.yml exec api chmod -R 775 vendor
```

### HMR Issues

If hot reload isn't working:

1. Check browser console for WebSocket errors
2. Ensure ports 3000 and 24678 are available
3. Try restarting the UI container:
   ```bash theme={null}
   docker compose -f docker-compose.dev.yml restart ui
   ```

### Dependency Installation Issues

If you need to force reinstall dependencies:

```bash theme={null}
# Remove the install marker to force reinstall
docker compose -f docker-compose.dev.yml exec ui rm -f node_modules/.install-complete

# Or clear the entire volume
docker volume rm opnform_client_node_modules
```

## Environment Variables

For production deployments, see our [Environment Variables](/configuration/environment-variables#docker-environment-variables) documentation.

<Note>
  Development mode doesn't use `.env` files. All configuration is embedded in
  `docker-compose.dev.yml` for simplicity. To modify variables, edit the
  `environment:` section directly in that file.
</Note>
