Get the Newsletter
Keep up on what's happening with RedwoodJS!
Get Some Swag
The Redwood logo on shirts, hats,
and more!
Get Free Stickers
Enter your address for a chance to get some, free!
Edge-ready
Redwood is designed to be deployable completely to the Edge—CDNs and serverless functions distributed everywhere. (Databases coming soon!)
Code Organization
Redwood has a pre-defined place for all your code— front-end and back-end. Components, layouts, pages, GraphQL, and services: they all have a home.
Developer Experience
Redwood apps are as declarative as possible; we eliminate most boilerplate; zero-config code splitting...everything Just Works™.
How it's Organized
Redwood places both the frontend and backend code in a single monorepo.
/web
contains the frontend and is served as static files through a CDN (and automatically code-split for you).
/api
contains the backend serverless functions (a GraphQL API by default) that your frontend will call when it needs
some dynamic data.
Routing
Redwood features its own router that brings some awesome innovation to this often overlooked (but important) part of your app. Named routes let you reference a route by a name you define, route param types take care of coercing values based on data type or custom functions, and more.
// web/src/Routes.js
import { Router, Route } from '@redwoodjs/router'
const Routes = () => {
return (
<Router>
<Route path="/" page={HomePage} name="home" />
<Route path="/users/{type}" page={UsersPage} name="users" />
</Router>
)
}
// web/src/components/Admin/Admin.js
import { Link, routes } from '@redwoodjs/router'
const Admin = () => {
return (
<h1><Link to={routes.home()}>My CRM</Link></h1>
<Link to={routes.users({type: "admin"})}>View Admins</Link>
)
}
Cells
The sequence of retrieving data from an API, showing a loading placeholder, and then displaying the result is so common that Redwood codifies it into a declarative code pattern, resulting in simple and readable code!
We call them cells and they contain the GraphQL query, loading, empty, error, and success states, each one rendering itself automatically depending on what state your cell is in.
// web/src/components/UsersCell/UsersCell.js
export const QUERY = gql`
query USERS {
users {
id
name
}
}
`
export const Loading = () => <div>Loading users...</div>
export const Empty = () => <div>No users yet!</div>
export const Failure = ({ message }) => <div>Error: {message}</div>
export const Success = ({ users }) => {
return (
<ul>
{ users.map(user => (
<li>{user.id} | {user.name}</li>
))}
</ul>
)
}
Services
Redwood puts all your business logic in one place—Services. These can be used by your GraphQL API or any other place in your backend code. Redwood does all of the annoying stuff for you.
Check out how easy it is to create and consume a GraphQL endpoint (we didn't even omit any other
import
statements or cheat to get the code smaller, honest!):
// api/src/graphql/users.sdl.js
export const schema = gql`
type User {
id: Int!
name: String!
}
type Query {
users: [User]
}
`
// api/src/services/users/users.js
import { db } from 'src/lib/db'
export const users = () => {
return db.user.findMany()
}
// web/src/components/UsersCell/UsersCell.js
export const QUERY = gql`
query USERS {
users {
id
name
}
}
`
export const Success = ({ users }) => {
return JSON.stringify(users)
}
Generators
Even with a relentless elimination of boilerplate, Redwood files still need a bit of code to get you started, and need to be created in the right directories. No problem, let a computer do that for you!
Redwood contains several generators which create the shell of cells, pages, layouts, services, and more. We even have a scaffold generator which will create all the pages necessary to run end-to-end CRUD operations on a database table.
# Create a cell for Users
$ yarn rw generate cell Users
# Create a layout named Admin
$ yarn rw generate layout Admin
# Create an About page and set the URL to /about
$ yarn rw generate page About /about
# Read the DB schema and create the SDL file for the User table
$ yarn rw generate sdl User
# Create api/src/services/email/email.js and include CRUD functions
$ yarn rw generate service Email --crud
# Create the SDL, service, cells, pages and components to CRUD a User
$ yarn rw generate scaffold User
Forms
Working with forms is notoriously annoying in React apps. Redwood removes the complexity and gives you the freedom to work with regular HTML inputs, but sprinkled with a bit of validation and error handling. Show client and server-side errors automatically and style them like any other React component.
// web/src/components/Comment/Comment.js
import { Form, Label, TextAreaField, FieldError, Submit } from "@redwoodjs/web"
export const Comment = () => {
const onSubmit = (data) => {
console.info(`Submitted: ${data}`)
}
return (
<Form onSubmit={onSubmit}>
<Label name="comment" errorStyle={{ color: "red" }} />
<TextAreaField
name="comment"
errorStyle={{ borderColor: "red" }}
validation={{ required: true }}
/>
<FieldError name="comment" errorStyle={{ color: "red" }} />
<Submit>Send</Submit>
</Form>
)
}
Ready for Redwood?