DEV Community

Cover image for How I Stopped Manually Syncing My TypeScript Frontend with Spring Boot Backend
Thomas
Thomas

Posted on

How I Stopped Manually Syncing My TypeScript Frontend with Spring Boot Backend

I spent an entire day rewriting my frontend code.

Not because I was adding new features. Not because I was fixing bugs.

But because I had updated some entities and endpoints on my Spring Boot backend.

Every TypeScript interface had to be manually rewritten. Every API call had to be updated. Every type had to match the new DTOs.

Hours of mind-numbing work. And the worst part? I knew I'd have to do it all over again the next time I touched the backend.

The Problem Every Full-Stack Developer Knows

If you work with Spring Boot and TypeScript, you know this pain:

  1. You update a Spring controller
  2. You update the corresponding DTOs
  3. Now your frontend is out of sync
  4. You manually create TypeScript interfaces
  5. You manually write new fetch calls
  6. You pray you didn't miss anything
  7. You get runtime errors because you DID miss something

There had to be a better way.

The Solution: Direct Code Generation

I decided to build a tool that would read my Spring controllers directly and generate TypeScript clients automatically.

No Swagger setup. No OpenAPI specs. No intermediate JSON files.

Just point it at your Spring Boot project and get type-safe TypeScript code.

Here's What It Looks Like

Your Spring Controller:

@RestController
@RequestMapping("/user")
public class UserController {

    @PostMapping("/login")
    public AuthResponse login(@RequestBody LoginDTO loginDTO) {
        return authService.login(
            loginDTO.getUsername(), 
            loginDTO.getPassword()
        );
    }

    @GetMapping("/info")
    public User getUserInfo() {
        return userService.getUserByUsername(
            SecurityContextHolder.getContext()
                .getAuthentication()
                .getPrincipal()
                .toString()
        ).orElseThrow();
    }
}
Enter fullscreen mode Exit fullscreen mode

Auto-Generated TypeScript:

import axios from 'axios';
import type { User } from './User';
import type { AuthResponse } from './AuthResponse';
import type { LoginDTO } from './LoginDTO';

export const login = (loginDTO: LoginDTO): Promise<AuthResponse> => 
    axios.post(`/user/login`, loginDTO)
        .then(response => response.data)
        .catch(error => { throw error });

export const getUserInfo = (): Promise<User> => 
    axios.get(`/user/info`)
        .then(response => response.data)
        .catch(error => { throw error });

// Interfaces generated too
export interface LoginDTO {
    username: string;
    password: string;
}

export interface AuthResponse {
    authenticationToken: string;
}

export interface User {
    username: string;
    roles: Array<RoleType>;
}

export enum RoleType {
    ADMIN = "ADMIN",
    USER = "USER",
}
Enter fullscreen mode Exit fullscreen mode

That's it. Update your backend? Run it again. Everything stays in sync.

What It Supports

The tool handles all the Spring annotations you'd expect:

  • @RequestBody
  • @PathVariable
  • @RequestParam
  • Pageable
  • @JsonIgnore
  • @Transient
  • Enums
  • Generic types
  • Complex nested objects

Why Not Just Use Swagger?

Fair question. There are tools like swagger-typescript-api that generate TypeScript clients from OpenAPI specs.

But here's the thing:

  1. Setup overhead - You need to configure Swagger/Springdoc first
  2. Extra dependencies - More stuff in your pom.xml/build.gradle
  3. Two-step process - Generate Swagger docs, THEN generate TypeScript
  4. Maintenance - Keep your Swagger annotations up to date

For enterprise projects with mature API documentation practices? Sure, Swagger makes sense.

But for MVPs, internal tools, and small teams that just want to build fast? Direct generation from Spring controllers is simpler.

The Results

I've been using this on every project since I built it.

I can't even remember the last time I had a type mismatch between my frontend and backend. Or a runtime error from an outdated API call.

Update the backend, run one command, move on with my life.

How It Works (Technical Overview)

Under the hood, the tool:

  1. Scans your Spring Boot application for @RestController classes
  2. Analyzes method signatures, annotations, and return types
  3. Traverses the object graph to find all DTOs and entities
  4. Maps Java types to TypeScript equivalents
  5. Generates interfaces and Axios functions
  6. Optionally commits everything to Git automatically

It integrates directly into your Spring Boot startup as a CommandLineRunner:

@Bean
public CommandLineRunner start(
    final RequestMappingHandlerMapping requestMappingHandlerMapping
) {
    return (args -> {
        final Spring2TSModule spring2TSModule = new Spring2TSModule(
            List.of("com.yourpackage"), 
            "output/ts/"
        );
        spring2TSModule.generate(requestMappingHandlerMapping);
    });
}
Enter fullscreen mode Exit fullscreen mode

Run your Spring app once, get all your TypeScript files.

Who This Is For

This tool is perfect if you:

  • Work with Spring Boot + TypeScript/React/Vue/Angular
  • Are tired of manually syncing frontend types with backend changes
  • Want type safety without the Swagger setup overhead
  • Build MVPs or internal tools that need to move fast
  • Value developer experience and automation

Try It Yourself

I'm making this available to other developers who face the same pain I did.

You can grab it here: https://thomasberrens.gumroad.com/l/spring2ts

It's a one-time payment with lifetime updates. If it saves you even one hour of manual type-syncing, it's worth it.

Also launching on Product Hunt tomorrow if you want to check it out there and provide feedback!


Have you dealt with this problem? What's your solution? Drop a comment below - I'd love to hear how other full-stack devs handle the Spring/TypeScript sync challenge.

Top comments (0)