Say goodbye to Rails frontend drama.
This monorepo template is designed for building a full-stack application using Ruby on Rails, TypeScript, React, Next.js, Shadcn, and Tailwind CSS.
https://github.com/user-attachments/assets/7a258124-871d-4810-8f9a-447dfa9f4233
rails-modern-stack-template
āāā apps - All applications are contained within here
ā āāā server - Rails API
ā āāā web - NextJS frontend
āāā packages - Internal packages to share code within your monorepo
ā āāā eslint-config - Linters
ā āāā servers - Generated types and API client from backend
ā āāā typescript-config - Shareable Typescript configs
ā āāā ui - Shadcn components
cd rails-modern-stack-template
pnpm install
cd apps/server
bundle install
rails db:create
rails db:migrate
rails db:seed
Run all services from the root directory:
pnpm run dev
Open your browser and go to http://localhost:3000
Use [email protected]
and after clicking on the login button, use the magic code from the console to log in.
Typegen is the core of this setup, helping you write backend code faster by automatically generating TypeScript API clients and types. When you define your API methods in Ruby on Rails, Typegen takes care of creating the matching TypeScript types and API client methods.
This eliminates the need for repetitive code, keeps things in sync between the backend and frontend, and helps you avoid errors. With Typegen, you can focus on the actual logic instead of manually handling API client code, making it an essential part of the workflow.
Define your API endpoints in apps/server/app/controllers/api. For example:
api_method 'users.identity', response: UserIdentityResponseSerializer
def identity
render_resource(UserIdentityResponseSerializer, user: current_user, ok: true)
end
And the corresponding serializer in apps/server/app/serializers/user_identity_response_serializer.rb
:
class UserIdentityResponseSerializer < BaseResponseSerializer
has_one :user, resource: UserSerializer
type(
user: [UserSerializer, optional: true]
)
end
This will generate the following TypeScript types:
export interface UserIdentityResponse {
user?: User | null
}
export type User = {
id: string,
email: string,
projects: Project[]
}
And API client methods:
export class Api<SecurityDataType extends unknown> extends HttpClient<SecurityDataType> {
users = {
identity: (data: any, params: RequestParams = {}) =>
this.request<UserIdentityResponse>({
path: 'users.identity',
method: "POST",
body: data,
secure: true,
type: ContentType.Json,
format: "json",
...params,
}),
}
}
Generate types by running:
pnpm run typegen