[← Back to knowledge base](/knowledge) # I Spent 11 Years in Spring Boot. Here's What I Had to Rebuild in TypeScript. TypeScript is the right language for AI-assisted development. NestJS out of the box is not Spring Boot. Here's everything I rebuilt to bridge the gap. Dathan Guiley·February 2026 I wrote my first Java Enterprise application at Fleet Numerical in Monterey, building weather visualization tools for the Navy on supercomputer clusters. That was the late nineties. For the next two decades, I lived in the JVM — Java, then Scala, Groovy, and finally Kotlin, which became my favorite language. Spring Boot was home. Then I moved to TypeScript and NestJS. Not because the JVM stopped working, but because TypeScript is the ideal language for AI-assisted development. AI tools understand it deeply. The ecosystem moves fast. And critically, one language runs everywhere — frontend, backend, scripts, infrastructure. But NestJS out of the box is not Spring Boot. Not even close. Here is everything I had to rebuild. ## JPA-level ORM convenience This was the big one. JPA — the Java Persistence API — is one of the most mature, battle-tested ORM systems ever built. Its convenience functions are incredibly robust and secure by default against injection attacks. After over a decade using it, you take things for granted that simply do not exist in the Node world. TypeORM is the closest thing to JPA in TypeScript, which is why I chose it. But the gap is significant. I had to rebuild safe query building patterns, pagination abstractions, and enum-to-column mapping conventions from scratch. One critical lesson I carried over: I never use JPA-style auto-joining, and I do not use it in TypeORM either. Automatic joins between entities lead to massive problems at scale — unexpected N+1 queries, circular references, and performance cliffs that surface in production, not in development. Instead, I populate joined information manually or create database views. This is a pattern most Spring Boot developers learn the hard way. I wanted it baked into the TypeScript codebase from day one. ## JSON mapping standards Jackson is the JSON serialization library for the JVM ecosystem, and it handles dozens of edge cases that you never think about until they bite you. Null handling conventions. Enum serialization and deserialization. Date format standards. Nested object mapping. Error responses. In TypeScript, you have to make all these decisions yourself. And if you do not make them explicitly, every developer — and every AI tool — will make different decisions in different places. I built a consistent set of serialization conventions that mirror what Jackson provides: explicit null handling, standardized date formats, predictable enum mapping. Boring? Absolutely. But these conventions prevent an entire category of bugs that are painful to track down. ## Pagination and safe query building Pagination sounds simple until you build it for real. Cursor-based versus offset-based. Total count queries that kill performance on large tables. Filter combinations that produce SQL injection vulnerabilities if you are not careful. Spring Boot with JPA gives you Pageable and Specification patterns that handle this elegantly. In TypeScript, I had to build the equivalent from the ground up — safe query builders that prevent injection by construction, not by developer discipline. A consistent pagination interface that works across every resource in the system. Filter parsing that composes cleanly without falling into SQL injection traps. This is the kind of infrastructure code that nobody celebrates but everyone depends on. Get it wrong and every endpoint in your application is subtly broken. ## Production logging and monitoring This one surprised me the most. The JVM ecosystem has decades of investment in observability. SLF4J, Logback, Micrometer — mature libraries with deep integration into every framework. You can add execution time metrics to any function with an annotation. Structured logging is a solved problem. In the Node world, the default is `console.log`. That is not production logging. I built a logging infrastructure that provides structured output with correlation IDs, execution time measurement on functions and endpoints, request-response logging with appropriate redaction, and proper log levels that can be configured per-module in production. When something goes wrong at two in the morning, the difference between `console.log` and proper observability is the difference between a fifteen-minute fix and a four-hour investigation. ## Naming and organization conventions NestJS inherited Angular's organizational patterns — modules, decorators, and a particular way of arranging files. It works, but it does not match how I think about systems after thirty years of building them. I reorganized everything to match a more traditional architecture: models in one place, controllers in another, repositories separate from services, configuration isolated. Not because Angular conventions are wrong — but because consistency with established patterns makes the codebase more legible to both humans and AI tools. This matters more than people realize. When an AI tool reads a NestJS project organized like a Spring Boot project, it brings all of its training on Spring Boot patterns to bear. The organizational structure is context that improves AI output. ## Why this matters for you You might be reading this thinking: "Who cares about your migration journey?" Fair question. Here is why it matters. If you are evaluating agencies or development partners, ask them what their codebase looks like. Not what frameworks they use — what patterns they have established, what conventions they enforce, and what problems they have already solved. An agency that starts every project from `npm init` is asking you to pay for them to solve these problems on your dime. An agency with a mature, battle-tested codebase gives you the benefit of hard-won lessons from day one. The Wilde Agency codebase exists because I refused to accept "good enough" when moving from the JVM to TypeScript. Every pattern I spent two decades relying on in Spring Boot has been deliberately re-implemented in TypeScript, often improved in the process. Every AI tool that works inside this codebase produces better output because of it. ## The thesis You cannot just `npm init` a NestJS project and call it enterprise-ready. The distance between a fresh NestJS installation and a production-grade codebase is enormous — and it is exactly the distance that separates software that works from software that lasts. Thirty years of patterns do not transfer automatically. They have to be deliberately rebuilt. That is the codebase. And that is why AI produces better code when it works inside it. Wilde Agency builds production software with AI-native architecture. [Apply for the architecture review](/start)