ForgeKit is a starter kit for SaaS web applications. Even though this is an experiment I am doing with AI, I am planning to make it as useful as possible.
The goal is to cover the parts every SaaS needs but nobody enjoys rebuilding: sign-in, organizations and teams, billing, and an audit trail. You clone it, set a few env values, and start on your actual product instead of a blank folder.
It is early and I am building it one feature at a time, so treat it as a work in progress rather than something to ship today. I am trying to keep it honest about what is actually enforced versus what is just a convenience.
apps/web: web app packageapps/api: API app packagepackages/ui: shared UI packagepackages/core: core domain packagepackages/db: database packagepackages/config: shared config packagetooling/typescript-config: strict TypeScript base configtooling/eslint-config: shared flat ESLint configtooling/vitest-config: shared Vitest config
The internal dependency flow is enforced by a custom ESLint rule that fails the build on forbidden cross-package imports. A forbidden import is any runtime package reaching past its allowed direct internal dependency, such as @forgekit/api importing @forgekit/db directly.
See docs/eslint-rules/dependency-flow.md for the full rationale and implementation details.
apps/webimports@forgekit/uiapps/apiimports@forgekit/corepackages/coreimports@forgekit/dbpackages/dbimports@forgekit/configpackages/uihas no internal dependencies
Packages build to dist and publish dist/index.js and dist/index.d.ts through main, types, and exports.
Run these from the repo root:
pnpm build
pnpm lint
pnpm typecheck
pnpm testThe workspace uses strict TypeScript with noUncheckedIndexedAccess. ESLint rejects explicit any.
A pre-push git hook runs the four gates (build, lint, typecheck, test) and blocks a push that fails any of them. It is installed on pnpm install by a prepare script that points git at the committed .githooks directory. Bypass it in a genuine emergency with git push --no-verify.
Two Turborepo behaviors to know:
- Turbo caches
build,test, andlintresults by input hash, so a green run may have been served from cache rather than actually run. Force a real run withTURBO_FORCE=true pnpm test. - Internal packages are consumed as their built
dist/, not their source. Running the gates through Turbo rebuilds dependencies in order, but a direct per-package command such aspnpm --filter @forgekit/api testcan read a staledist/. Rebuild first, or run through Turbo.
A collaboration between a human and an AI 👨 ❤️ 🤖