Skip to main content
The easiest way to get started with OpnForm is through our official managed service in the Cloud. It takes just 1 minute to start building forms with the free plan, with high availability, backups, security, and maintenance all managed for you.

Overview

OpnForm provides a minimal Docker-based development environment optimized for local development. While the full architecture is detailed in our Docker Deployment 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:
  2. Run the setup script in development mode:
    This script will:
    • Pull or build required Docker images
    • Start all containers in development mode with embedded configuration
    • Display access information
    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.
  3. Access your development environment:

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.
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.

Architecture

The development setup is intentionally simplified compared to our Docker Deployment 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:
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.
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.

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)
  • 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
    • Direct access to Nuxt dev server with HMR
    • Vue DevTools available
    • All client-side routing handled directly
  • 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
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.

File Structure

The development setup mounts your local directories into the containers:

Common Tasks

Running Commands

To run commands in the containers:

Accessing Logs

View container logs:

Database Access

The PostgreSQL database is accessible:
  • From containers: host=db
  • From your machine: localhost:5432
  • Default credentials:

Troubleshooting

Container Issues

If containers aren’t starting properly:

Frontend Access Issues

If you get 503 errors when accessing the frontend:
1

Use IPv4 address

Always use http://127.0.0.1:3000 instead of http://localhost:3000
localhost can resolve to IPv6 (::1) on some systems, causing connection issues with Docker’s port binding.
2

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/"
3

Restart containers if needed

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:

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:

Dependency Installation Issues

If you need to force reinstall dependencies:

Environment Variables

For production deployments, see our Environment Variables documentation.
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.