| name | framework-folder |
| description | Enforce separation between framework and app code in app/framework/. Use when adding new files or logic to app/framework/, importing framework modules, or deciding where to place new abstractions. |
Framework Folder
The app/framework/ folder must contain zero app-specific logic. It should be self-contained enough to extract as a separate npm package at any time.
What Belongs in app/framework/
Only reusable abstractions that apply across any app built on this framework:
- Database connection and helpers (
db.server.ts)
- Session management (
sessions.server.ts)
- Flash messages (
flash.server.ts)
- Email transport setup (
email.server.ts) — the makeSendEmail factory, not app-specific email config
- Environment variable utilities (
env.server.ts) — the makeTypedEnvironment factory and framework-only env schema
- Route controller helpers (
controllers.server.ts) — act(), load()
- Auth utilities (
auth.server.ts)
- Background job utilities (
worker.server.ts) — makeJob, makeCronJob
What Does NOT Belong in app/framework/
- App-specific environment variables (e.g.,
SENDGRID_API_KEY, GOOGLE_*, AWS_*)
- App-specific business logic or domain models
- App-specific configurations (e.g., SMTP credentials, S3 bucket names)
- Anything that references
app/business/ or app-specific modules
Import Direction
The dependency flow is strictly one-directional:
app/business/ → imports from → app/framework/
app/routes/ → imports from → app/framework/
app/email.server.tsx → imports from → app/framework/
app/framework/ → NEVER imports from → app/business/, app/routes/, or app-level files
Framework files may import from each other using relative paths (./env.server).
The Factory Pattern
When framework code needs app-specific configuration, expose a factory function that the app calls with its own config:
function makeSendEmail(config: SMTPTransport.Options & { maildevPort: number; maildevWebPort: number }) {
}
const sendEmail = makeSendEmail({
maildevPort: 1027,
maildevWebPort: 1082,
host: 'smtp.sendgrid.net',
})
Litmus Test
Before adding anything to app/framework/, ask:
- Would another app built on this framework need this?
- Does it reference any app-specific modules or env vars?
- Could this be published as part of a standalone npm package?
If the answer to #1 is no, or #2 is yes, or #3 is no — it belongs in app/ or app/business/ instead.