The Tern Project
The Tern Project is a fat-free, opinionated web framework built on convention over configuration, removing boilerplate while maintaining a clear mental model through unified routing and schema-first validation. It is designed for teams who want a straightforward, cohesive foundation for the modern web — one that glues together the necessary layers of a full-stack application without the cognitive overhead of a fragmented library stack.
Core Philosophy
At its heart, Tern is about removing friction. Modern web development often forces developers to spend more time wiring libraries together than actually building features. Tern solves this by providing a thin but useful abstraction layer that makes the right path the easiest path:
- Fat-Free: The runtime stays lean. Tern does not attempt to be a platform; it provides the scaffolding so you can plug in your own tools for the database, auth, and asset management.
- Convention over Configuration: A standardized directory structure and auto-wiring mean that new team members can land and be productive immediately; the framework already knows where the controllers live and how dependencies should be resolved.
- One Mental Model: Instead of jumping between a router, a validator, and a controller, everything is unified. The route definition is the source of truth for how a request enters the system.
Key Architectural Pillars
Tern rests on three main pillars that define the developer experience and the system's behavior:
Unified Routing
Routes are declared in a single, centralized location. Each route entry encapsulates the path, the HTTP method, the associated middleware chain, and the validation schema for the request body. This co-location eliminates the "ping-pong" effect of checking the router for the path and then hunting through the codebase for the validation logic.
Schema-First Development
Data integrity is enforced at the boundary. Every writable endpoint requires a schema that serves two purposes:
- Validation: Requests that do not match the schema are rejected before they ever reach your business logic.
- Serialization: The same schema defines the shape of the response, ensuring that the API contract is always in sync with the validation rules.
By sharing this contract, the frontend and backend are always speaking the same language, and the compiler can verify that the data flowing through the system matches what the application expects.
Convention-Driven Wiring
Tern automates the plumbing of a web application. Controllers are automatically wired and dependencies are resolved by convention rather than manual injection in every endpoint. This keeps controllers pure and focused on business logic rather than infrastructure concerns, making them easier to test in isolation.
Request Lifecycle
A request through Tern follows a predictable pipeline:
- Routing: The request is matched against the unified routing table.
- Middleware: The request passes through the declared middleware chain (e.g., auth, logging, rate-limiting).
- Validation: The request body is validated against the route's schema.
- Dispatch: The validated request data is injected into the controller.
- Response: The controller returns a result that is automatically serialized according to the schema.
Why Tern?
The JavaScript ecosystem is fragmented; you spend too much time gluing libraries together. Tern glues them for you with a thin abstraction — enough to be useful, light enough to be transparent. It is the "boring" choice for the modern web — a sensible, opinionated foundation that lets you focus on building the product, not the framework.
For large teams that may need more granular control, the architecture is still extensible: the dispatcher can be overridden with a custom routing engine, and the middleware system allows for specialized chains for complex domains.
Developer Experience
Tern ships with a complete developer toolchain:
- Hot Reloading: Changes to routes or controllers are reflected instantly in the dev server.
- Typed Endpoints: The unified routing model enables end-to-end type safety across the stack.
- Integrated Testing: A built-in test runner allows you to spin up an ephemeral instance of the app and run integration tests against the real routing and validation layers.
One command to start the dev server, one command to run the tests — that is the Tern promise.