The Web Application is the core user-facing component of Trigger.dev, built using the Remix framework with React. It provides a server-rendered dashboard for managing organizations, projects, environments, tasks, and runs, along with a comprehensive REST API for SDK and CLI integration. The application supports both traditional HTTP routes and real-time connections via Server-Sent Events (SSE) and WebSockets.
This page covers the overall architecture, server infrastructure, rendering strategy, and deployment patterns. For specific subsystems, see Application Architecture for Remix integration details, Navigation and Routing for URL management, UI Components and Styling for the design system, Run Monitoring and Visualization for task execution views, Realtime Updates for SSE/WebSocket integration, and Authentication and Authorization for security patterns.
The webapp is a full-stack Remix application that serves three primary functions:
/api/v1, /api/v3)The application runs on Node.js with Express as the HTTP server, supporting optional clustering for horizontal scalability. It integrates with PostgreSQL (via Prisma), Redis (for caching and queues), and OpenTelemetry for observability.
Technology Stack:
| Component | Technology | Purpose |
|---|---|---|
| Framework | Remix 2.1.0 | Server-side rendering, routing, data loading |
| UI Library | React 18.2.0 | Component rendering |
| Server | Express 4.20.0 | HTTP server, middleware |
| Styling | Tailwind CSS 3.4.1 | Utility-first CSS framework |
| Forms | @conform-to/react 0.9.2 | Form validation and handling |
| Real-time | Socket.io 4.7.4, WebSocket | Live updates |
| ORM | Prisma (via @trigger.dev/database) | Database access |
| Observability | OpenTelemetry 2.0.1 | Distributed tracing |
| Error Tracking | Sentry 9.46.0 | Error monitoring |
Sources: apps/webapp/package.json1-291
Sources: apps/webapp/server.ts1-269 apps/webapp/app/entry.server.tsx1-258 apps/webapp/app/entry.client.tsx1-16 apps/webapp/app/root.tsx1-133
The application has distinct entry points for server-side and client-side execution:
apps/webapp/app/entry.server.tsx29-74 exports handleRequest() which orchestrates server-side rendering:
isbot() to determine rendering strategyAccept-Language header and User-Agent for locale/platformhandleBotRequest() waits for onAllReady() to ensure complete HTMLhandleBrowserRequest() streams from onShellReady() for faster TTFB<RemixServer> in OperatingSystemContextProvider and LocaleContextProviderThe server also initializes critical systems on startup:
Worker.init() → bootstrap() → Initialization sequence
- registerRunEngineEventBusHandlers() (singleton)
- setupBatchQueueCallbacks() (singleton)
- eventLoopMonitor (if enabled)
- resourceMonitor (if enabled)
Sources: apps/webapp/app/entry.server.tsx29-258
apps/webapp/app/entry.client.tsx6-15 hydrates the server-rendered HTML:
The same context providers ensure consistent behavior between SSR and CSR.
Sources: apps/webapp/app/entry.client.tsx1-16
apps/webapp/app/root.tsx108-132 defines the application shell:
<html> → <head> (Meta, Links) → <body>
├── ShortcutsProvider (keyboard shortcuts)
├── <Outlet /> (route content)
├── Toast (notifications)
├── ScrollRestoration
├── ExternalScripts
└── Scripts, LiveReload
The loader at apps/webapp/app/root.tsx48-71 provides global data:
getUser())featuresForRequest())Sources: apps/webapp/app/root.tsx1-133
apps/webapp/server.ts91-268 configures the Express application:
Middleware Stack:
| Order | Middleware | Purpose |
|---|---|---|
| 1 | compression() | GZIP response compression (unless disabled) |
| 2 | express.static() | Static asset serving with cache headers |
| 3 | morgan('tiny') | HTTP request logging |
| 4 | Custom headers | Security headers (HSTS, X-Robots-Tag, CSP) |
| 5 | runWithHttpContext() | Request ID generation for tracing |
| 6 | apiRateLimiter | Rate limiting for API routes |
| 7 | engineRateLimiter | Rate limiting for engine routes |
| 8 | createRequestHandler() | Remix request handler |
Static Asset Strategy:
/build/* → Cache forever (maxAge: "1y", immutable: true) - fingerprinted assetsmaxAge: "1h") - favicon, etc.Sources: apps/webapp/server.ts91-186
Clustering Configuration:
apps/webapp/server.ts18-21 determines worker count:
ENABLE_CLUSTER=1 → cluster mode enabled
WORKERS = WEB_CONCURRENCY || CLUSTER_WORKERS || os.availableParallelism()
Primary Process Responsibilities:
Worker Process Responsibilities:
Sources: apps/webapp/server.ts18-90
apps/webapp/server.ts228-263 implements protocol-aware WebSocket upgrades:
Socket.io Configuration:
@socket.io/redis-adapter)WebSocket (WSS) Configuration:
/ws onlySources: apps/webapp/server.ts228-263
apps/webapp/remix.config.js1-42 configures the Remix build:
| Setting | Value | Purpose |
|---|---|---|
serverModuleFormat | "cjs" | CommonJS output for Node.js |
serverDependenciesToBundle | Array of patterns | Bundle ESM-only packages |
browserNodeBuiltinsPolyfill | Object | Polyfill Node.js modules for browser |
tailwind | true | Enable Tailwind CSS integration |
ignoredRouteFiles | ["**/.*"] | Ignore hidden files as routes |
Critical Bundled Dependencies:
@trigger.dev/* packages - internal monorepo code@internal/* packages - shared utilitiesremix-utils, marked, superjson, p-limit, etc.This ensures the server bundle is self-contained and doesn't require external module resolution at runtime.
Sources: apps/webapp/remix.config.js1-42
turbo.json16-31 defines build dependencies:
webapp#start → depends on ^build (all dependencies must build first)
├── outputs: public/build/**
└── command: node --max-old-space-size=8192 ./build/server.js
apps/webapp/package.json7-21 scripts:
| Script | Command | Purpose |
|---|---|---|
build | run-s build:** && upload:sourcemaps | Multi-step build process |
build:remix | remix build --sourcemap | Compile Remix app |
build:server | esbuild server.ts | Bundle Express server |
build:sentry | esbuild sentry.server.ts | Bundle Sentry integration |
dev | remix dev | Development server with HMR |
start | node ./build/server.js | Production server |
typecheck | tsc --noEmit | Type checking (no emit) |
Sources: turbo.json16-31 apps/webapp/package.json6-22
The application loads configuration from multiple sources with precedence:
.env file (via dotenv - apps/webapp/package.json143)env.server.tsCritical Configuration:
| Variable | Purpose | Default |
|---|---|---|
NODE_ENV | Environment mode | development |
PORT / REMIX_APP_PORT | HTTP server port | 3000 |
DATABASE_URL | PostgreSQL connection | Required |
REDIS_HOST / REDIS_PORT | Redis connection | Required |
SESSION_SECRET | Cookie signing | Required |
APP_ORIGIN | Base URL | Required |
ENABLE_CLUSTER | Clustering mode | 0 |
WEB_CONCURRENCY | Worker count | CPU count |
DASHBOARD_AND_API_DISABLED | Disable routes | false |
HTTP_SERVER_DISABLED | Disable HTTP | false |
ALLOW_ONLY_REALTIME_API | Realtime-only mode | false |
Deployment Modes:
The server supports specialized deployment configurations:
/realtime routes and /healthcheck apps/webapp/server.ts156-167Sources: apps/webapp/server.ts113-267 turbo.json119-141
apps/webapp/server.ts1 imports Sentry configuration first:
apps/webapp/app/entry.server.tsx180-194 wraps error handler:
The application automatically instruments:
| Package | Instrumentation | Configuration |
|---|---|---|
@opentelemetry/instrumentation-http | HTTP requests/responses | apps/webapp/package.json74 |
@opentelemetry/instrumentation-express | Express middleware | apps/webapp/package.json74 |
@opentelemetry/instrumentation-aws-sdk | AWS SDK calls | apps/webapp/package.json73 |
@prisma/instrumentation | Prisma queries | apps/webapp/package.json85 |
Traces, metrics, and logs export via OTLP to external backends.
Sources: apps/webapp/package.json65-86
apps/webapp/app/entry.server.tsx245-257 conditionally enables monitoring:
These monitor Node.js event loop lag and system resources (CPU, memory).
apps/webapp/app/entry.server.tsx212-234 handles process-level errors:
This prevents Prisma connection errors from crashing the entire process while still exiting for critical errors.
Sources: apps/webapp/app/entry.server.tsx212-258
apps/webapp/app/utils/httpErrors.ts1-25 provides user-friendly error messages:
apps/webapp/app/root.tsx83-106 defines the error boundary:
This ensures errors are displayed with the full application shell (keyboard shortcuts, layout) but without requiring user context.
Sources: apps/webapp/app/utils/httpErrors.ts1-25 apps/webapp/app/root.tsx83-106
apps/webapp/package.json11 runs the development server:
This starts Remix in watch mode, which:
The custom server enables:
apps/webapp/tsconfig.json1-29 configures TypeScript:
The ~/ path alias maps to app/ for clean imports throughout the codebase.
Sources: apps/webapp/package.json11-21 apps/webapp/tsconfig.json1-29
The webapp is typically deployed as a container with:
pnpm build → compile Remix + serverGET /healthcheck endpointHorizontal Scaling:
Sources: apps/webapp/server.ts187-269
apps/webapp/server.ts127-143 sets security headers:
| Header | Value | Purpose |
|---|---|---|
Strict-Transport-Security | max-age=31536000000 (~100 years) | Force HTTPS |
X-Robots-Tag | noindex, nofollow (non-prod) | Prevent search indexing |
X-Frame-Options | SAMEORIGIN (login pages) | Prevent clickjacking |
Content-Security-Policy | frame-ancestors 'self' (login) | Additional frame protection |
Referrer-Policy | strict-origin-when-cross-origin | Limit referrer info |
X-Content-Type-Options | nosniff | Prevent MIME sniffing |
Permissions-Policy | Restrict hardware features | Disable geolocation, camera, etc. |
apps/webapp/app/root.tsx23-28 sets additional headers in root loader.
Sources: apps/webapp/server.ts126-143 apps/webapp/app/root.tsx23-28
With Task Execution Engine:
With Database:
With Redis:
With External Services:
Sources: apps/webapp/package.json28-219
Refresh this wiki
This wiki was recently refreshed. Please wait 2 days to refresh again.