TypeScript in 2025 | Full-Stack Development with Bun, Astro, and Modern Frameworks
Why TypeScript dominates full-stack development in 2025. Real-world insights on Bun runtime, Astro, NestJS, and building production applications entirely in TypeScript.
thelacanians
The Argument Is Over
Five years ago, you could have a reasonable debate about whether TypeScript was worth the overhead. That debate is settled. TypeScript is not just the default for new projects — it is the expectation. Try submitting a pull request with untyped JavaScript to any serious open-source project in 2025 and see what happens.
At The Lacanians, we build everything in TypeScript. Frontend, backend, CLIs, infrastructure scripts, configuration files. The only exception is when we reach for Go (which we do for specific performance-critical tools like our CLI framework, nexo). Everything else is TypeScript, and this post explains why.
The Ecosystem Has Matured
TypeScript’s strength was always the type system. What changed in the last two years is everything around the type system.
Bun Changes the Runtime Story
Node.js served us well for a decade. Bun makes it feel antiquated. The performance improvements are significant, but the real value is the developer experience:
# Initialize a project
bun init
# Install dependencies (faster than npm, yarn, or pnpm)
bun install
# Run TypeScript directly -- no build step, no ts-node
bun run src/index.ts
# Built-in test runner
bun test
# Bundle for production
bun build ./src/index.ts --outdir ./dist
No tsconfig.json gymnastics. No choosing between ts-node, tsx, and esbuild-register. No separate test framework installation. Bun runs TypeScript natively, and it does so at a speed that makes the compile-step complaint irrelevant.
We have migrated most of our internal tooling to Bun. Our secret management tool, tinyvault, runs on Bun. Our knowledge base, noted, runs on Bun. The development loop is measurably faster.
Framework Convergence
The framework landscape has consolidated around a few excellent options, all TypeScript-first:
Astro for content and marketing sites. This site is built with Astro. The content collections API with Zod schema validation is exactly right for structured content:
// Type-safe content collections
const blog = defineCollection({
schema: z.object({
title: z.string(),
pubDate: z.coerce.date(),
category: z.enum(['Engineering', 'AI & Development', 'Startup']),
tags: z.array(z.string()),
}),
});
// Query with full type inference
const posts = await getCollection('blog');
// posts[0].data.category is typed as the enum, not string
Next.js and Nuxt for full-stack applications. Server components, API routes, middleware — all typed end-to-end. We use Nuxt for Vue projects and Next.js for React projects, choosing based on client preference and team familiarity.
NestJS for backend services that need structure. When a project outgrows a few API routes and needs proper dependency injection, request validation, and middleware pipelines, NestJS provides Rails-like structure with full TypeScript support.
Type Safety Is Not Optional Anymore
The argument for types used to be abstract: “it catches bugs.” In 2025, the argument is concrete: types are the contract layer for your entire application.
Database to UI Type Safety
With tools like Drizzle ORM or Prisma, your database schema generates TypeScript types. Those types flow through your API layer, into your frontend components, and all the way to the rendered UI. A column rename in your database becomes a compile-time error in your React component.
// Schema definition (Drizzle)
export const users = pgTable('users', {
id: serial('id').primaryKey(),
email: varchar('email', { length: 255 }).notNull().unique(),
plan: varchar('plan', { length: 50 }).$type<'free' | 'pro' | 'enterprise'>(),
});
// Inferred type flows everywhere
type User = typeof users.$inferSelect;
// { id: number; email: string; plan: 'free' | 'pro' | 'enterprise' | null }
// API endpoint -- return type is inferred
export async function getUser(id: number) {
return db.select().from(users).where(eq(users.id, id));
}
// Component -- type errors if schema changes
function UserBadge({ user }: { user: User }) {
// TypeScript knows user.plan is 'free' | 'pro' | 'enterprise' | null
return <span className={planStyles[user.plan ?? 'free']}>{user.plan}</span>;
}
When we renamed a field in a client’s database last month, TypeScript surfaced 23 places in the codebase that needed updating. Without types, those would have been 23 runtime errors discovered by users.
AI Understands Types
This is an underappreciated benefit. When you use AI tools like Claude or Copilot in a typed codebase, the quality of generated code improves dramatically. The AI reads your type definitions as specification. It knows what shape the data has, what functions accept, and what components expect.
In untyped JavaScript, AI has to guess. In TypeScript, it reads the contract and generates code that conforms to it. We have measured this informally across our projects: AI-generated code in typed codebases requires roughly 40% fewer corrections than equivalent code in untyped codebases.
Our TypeScript Stack in Practice
Here is the concrete stack we reach for on most projects:
| Layer | Tool | Why |
|---|---|---|
| Runtime | Bun | Speed, native TS, built-in tooling |
| Frontend Framework | Astro / Next.js / Nuxt | Depends on project type |
| Styling | Tailwind CSS | Utility-first, no context switching |
| Database | PostgreSQL + Drizzle | Type-safe queries, great migrations |
| API | tRPC or NestJS | End-to-end types or structured backend |
| Validation | Zod | Runtime + compile-time validation |
| Testing | Vitest / Bun test | Fast, TypeScript-native |
| CI/CD | GitHub Actions | Reliable, well-integrated |
Every layer speaks TypeScript. When we define a Zod schema for form validation, that same schema validates API input, generates TypeScript types, and can even generate OpenAPI documentation. One definition, used everywhere.
The Go Exception
We are not purists. Some problems are better solved in Go, and we reach for it when appropriate. Our CLI framework nexo is built in Go because CLIs benefit from single-binary distribution, minimal startup time, and low memory overhead. Go delivers all three.
The decision framework is simple:
- TypeScript when you need rapid iteration, a rich ecosystem of libraries, or full-stack web development
- Go when you need compiled binaries, maximum concurrency, or minimal resource usage
For about 90% of what we build, TypeScript is the answer.
Practical Advice for Teams
If you are starting a new project in 2025, here is our opinionated advice:
Use Bun. The risk is minimal at this point. Bun’s Node.js compatibility is excellent, and the developer experience improvement is immediate.
Pick one framework and commit. Do not use Next.js for some pages and Astro for others. Pick the one that matches your primary use case and build everything in it.
Invest in your type definitions. Spend extra time on your Zod schemas, database types, and API contracts. These are not boilerplate — they are the specification for your entire application. Every hour spent on type definitions saves ten hours of debugging.
Use strict mode. Set "strict": true in your tsconfig.json and never turn it off. The short-term pain of satisfying the type checker prevents the long-term pain of runtime errors.
{
"compilerOptions": {
"strict": true,
"noUncheckedIndexedAccess": true,
"noUnusedLocals": true,
"noUnusedParameters": true
}
}
Let AI write the implementation, you write the types. Define the interfaces, the schemas, the function signatures. Let Claude fill in the bodies. This is the most productive AI-assisted workflow we have found: humans define the contracts, AI implements them, TypeScript verifies the result.
TypeScript Is Infrastructure
TypeScript is no longer just a language choice. It is infrastructure. It is the type system that connects your database to your UI. It is the specification language that AI tools read to generate correct code. It is the contract layer that lets a team of five developers move as fast as a team of one without stepping on each other.
We build everything with it because it makes everything else we do — AI-assisted development, rapid prototyping, production deployment — better. That is not hype. That is ten years of shipping software.