This page introduces the Trigger.dev webapp, a Remix 2.1.0 application running on Express that serves as the central control plane for the entire system. The webapp provides the dashboard UI, hosts API endpoints for task triggering and management, handles real-time updates, and orchestrates task execution across the infrastructure.
For detailed information on specific subsystems:
The webapp is the primary interface between developers and the Trigger.dev platform. It serves multiple critical roles:
The application is designed to run both as a single-instance development server and as a horizontally-scaled production deployment with clustering support.
Sources: apps/webapp/package.json1-289 server.ts1-269
| Category | Package | Version | Purpose |
|---|---|---|---|
| Framework | @remix-run/react | 2.1.0 | Full-stack React framework with server-side rendering |
| Server | express | 4.20.0 | HTTP server with middleware support |
| Database ORM | @prisma/client | 6.14.0 | Type-safe PostgreSQL queries with read replica support |
| Caching/Locks | ioredis | 5.3.2 | Redis client for distributed state |
| Real-time | socket.io | 4.7.4 | WebSocket communication with fallbacks |
| Background Jobs | graphile-worker | 0.16.6 | PostgreSQL-based job queue |
| Validation | zod | 3.25.76 | Runtime type validation |
| Auth | remix-auth | 3.6.0 | Authentication framework |
| Observability | @opentelemetry/* | 0.203.0 / 2.0.1 | Distributed tracing |
Sources: apps/webapp/package.json32-216
The webapp acts as the central nervous system connecting all Trigger.dev components:
Sources: server.ts91-268 app/root.tsx1-133 app/entry.server.tsx1-258 apps/webapp/app/components/navigation/SideMenu.tsx1-614 apps/webapp/app/utils/pathBuilder.ts1-504
The Express server in server.ts91-179 configures the HTTP layer with:
compression(), disabled if DISABLE_COMPRESSION=1/build artifacts: immutable: true, maxAge: "1y"/public assets: maxAge: "1h"nanoid() assigned per requestrunWithHttpContext({ requestId, path, host, method }, next) with AsyncLocalStorageapiRateLimiter from build.entry.module.apiRateLimiterengineRateLimiter from build.entry.module.engineRateLimiterStrict-Transport-Security: max-age=3153600000X-Robots-Tag: noindex, nofollow (except on cloud.trigger.dev)The server supports horizontal scaling via Node.js cluster module server.ts15-89:
Configuration server.ts18-21:
Primary Process Responsibilities server.ts23-89:
WORKERS worker processes via cluster.fork() server.ts23-27SIGTERM/SIGINT to all workers server.ts34-43node webapp-server primary server.ts74Worker Process server.ts91-268:
node webapp-worker-{id} or node webapp-server server.ts109-111closeServer() on graceful shutdown server.ts209-220The server handles WebSocket upgrades for two protocols server.ts228-263:
Socket.IO Upgrade server.ts238-244:
Used for bidirectional communication with:
apps/coordinator)WebSocket Upgrade server.ts246-263:
Used for development mode real-time task execution streaming
The webapp uses Prisma Client with two connection types app/db.server.ts:
DATABASE_READ_REPLICA_URL configured)$transaction utility with OpenTelemetry tracingConfiguration from app/env.server.ts31-46:
All environment variables are centrally managed and validated using Zod schemas in app/env.server.ts28-683 Categories include:
Sources: app/env.server.ts1-683 server.ts91-268
apps/webapp/
├── app/ # Remix application code
│ ├── routes/ # Route handlers
│ │ ├── api.*.ts # REST API endpoints
│ │ ├── realtime.*.ts # SSE streaming endpoints
│ │ ├── otel.*.ts # OpenTelemetry ingestion
│ │ └── $orgSlug.*/ # Dashboard UI routes
│ ├── components/ # React components
│ │ ├── primitives/ # Base UI components
│ │ ├── layout/ # Layout components
│ │ └── runs/ # Run visualization
│ ├── services/ # Business logic services
│ ├── presenters/ # Data aggregation for loaders
│ ├── v3/ # V3 task system code
│ │ ├── services/ # Task management services
│ │ ├── marqs/ # MARQS queue implementation
│ │ └── handleSocketIo.server.ts # Socket.IO setup
│ ├── db.server.ts # Prisma client configuration
│ ├── env.server.ts # Environment variable schema
│ ├── root.tsx # Root layout component
│ ├── entry.server.tsx # Server-side entry point
│ └── entry.client.tsx # Client-side hydration
├── prisma/ # Database utilities
│ ├── seed.ts # Database seeding
│ └── populate.ts # Test data generation
├── public/ # Static assets
├── build/ # Compiled output
├── server.ts # Express server entry
└── package.json # Dependencies and scripts
| File | Purpose |
|---|---|
| server.ts1-269 | Express server setup, clustering, WebSocket upgrades |
| app/root.tsx1-133 | Root Remix component with global context providers |
| app/entry.server.tsx1-258 | Server-side rendering, bot detection, error handling |
| app/entry.client.tsx1-16 | Client-side hydration with React context |
| app/db.server.ts | Prisma client with read replica support |
| app/env.server.ts1-683 | Environment variable validation and configuration |
Sources: server.ts1-269 app/root.tsx1-133 app/entry.server.tsx1-258
Sources: server.ts91-179 app/entry.server.tsx122-172 apps/webapp/app/routes/api.v1.tasks.$taskId.trigger.ts
The webapp is containerized using a multi-stage Dockerfile docker/Dockerfile1-116:
prune --scope=webapp --docker to extract minimal dependency treepnpm run generate for Prisma and other codegenpnpm run build --filter=webapp... using TurboThe docker/scripts/entrypoint.sh1-51 script runs on container start:
wait-for-it.sh to ensure PostgreSQL is readypnpm --filter @trigger.dev/database db:migrate:deployCLICKHOUSE_URL is setNODE_MAX_OLD_SPACE_SIZESources: docker/Dockerfile1-116 docker/scripts/entrypoint.sh1-51
Turbo manages the build pipeline turbo.json1-147 The webapp build:
Build scripts from apps/webapp/package.json7-23:
Sources: turbo.json4-14 apps/webapp/package.json7-23 docker/Dockerfile66-74
On server startup, multiple initialization routines run app/entry.server.tsx190-257:
Graphile Worker entry.server.tsx190-192:
Initializes the background job system from ~/services/worker.server. This starts the graphile-worker pool that processes background jobs like:
Bootstrap entry.server.tsx194-196:
Runs environment setup from ~/bootstrap including:
Run Engine Event Handlers entry.server.tsx230:
Registers event bus handlers from ~/v3/runEngineHandlers.server that react to:
RUN_CREATED: Initialize run trackingRUN_STARTED: Update execution metadataRUN_COMPLETED: Process completion hooksRUN_FAILED: Trigger retry logic or alertsEvent Loop Monitor entry.server.tsx245-247:
Monitors event loop lag to detect blocking operations. Logs warnings when the loop is blocked beyond threshold.
Resource Monitor entry.server.tsx255-257:
Tracks memory usage, CPU usage, and heap statistics at 1-second intervals.
Remote Builds entry.server.tsx249-253:
Determines whether to use Depot for remote Docker builds or local buildx based on DEPOT_TOKEN presence.
The server installs a process.on('uncaughtException') handler entry.server.tsx206-228 that:
Prisma.PrismaClientKnownRequestError or Prisma.PrismaClientUnknownRequestErrorSources: app/entry.server.tsx190-258 server.ts1-269
The webapp adapts behavior based on NODE_ENV:
| Feature | Development | Production |
|---|---|---|
| Clustering | Disabled (single worker) | Optional via ENABLE_CLUSTER=1 server.ts18 |
| Live Reload | Enabled via broadcastDevReady() server.ts194-198 | Disabled |
| Source Maps | Generated | Generated + uploaded to Sentry apps/webapp/package.json23 |
| Hot Module Reload | Supported by Remix | N/A |
| Dev Queue Consumer | Active (if WORKER_ENABLED=true) | Active |
| Broadcast Dev Ready | Enabled | Disabled |
| Bot Detection | Full SSR (onAllReady) entry.server.tsx87-101 | Streaming SSR (onShellReady) entry.server.tsx139-153 |
| Process Title | node webapp-server server.ts109-111 | node webapp-server or node webapp-worker-{id} |
This triggers Remix's hot module reload (HMR) system to notify the client that the server is ready, enabling live reload on file changes.
Bots receive the complete HTML after all data fetching completes, while browsers receive streaming HTML for faster time-to-first-byte.
Sources: server.ts109-198 app/entry.server.tsx23-172
The app/env.server.ts1-683 file organizes configuration into logical groups:
Each variable is validated with Zod schemas that provide:
z.coerce.number())Sources: app/env.server.ts1-683
The .cursor/rules/webapp.mdc file outlines testing best practices .cursor/rules/webapp.mdc14-21:
Ideally, the
env.server.tsfile would never be imported into a test file, either directly or indirectly. Tests should only imported classes and functions from a file matchingapp/**/*.tsof the webapp, and that file should not use environment variables, everything should be passed through as options instead.
This "service/configuration" separation pattern is demonstrated in:
app/services/realtimeClient.server.ts (testable, accepts configuration)app/services/realtimeClientGlobal.server.ts (singleton with env vars)Sources: .cursor/rules/webapp.mdc1-41
Refresh this wiki