Before getting started, you should know this is alpha software. Blitz is incomplete. There are rough spots and bugs. APIs may change. But you can build an app and deploy it to production. We're excited to see what you build!
If you have any issues at all, please open an issue or join the Blitz slack and talk to us in the #help channel. If you get stuck and frustrated, please don't blame yourself. This user guide, and Blitz in general, is not yet fine-tuned for those with less experience. But eventually, it will be because this is very important to us.
Blitz is a Rails-like framework for building monolithic, full-stack React apps. The idea is that Blitz makes you extremely productive by doing as much set up and grunt work for you.
When building a Blitz app, you don’t have to think about “building an API” or “fetching data from your API”. You only think about writing functions that get and change data. And to use those functions in your component, you simply import and call them like a regular function.
Blitz is built on Next.js, so if you are familiar with that, you will feel right at home.
- You need Node.js 12 or newer
npm install -g blitz
oryarn global add blitz
- Run
blitz new myAppName
to create a new blitz app in themyAppName
directory cd myAppName
blitz start
- View your baby app at http://localhost:3000
By default, Blitz uses Prisma 2 which is a strongly typed database client. You probably want to read the Prisma 2 documentation. Note, Prisma 2 is not required for Blitz. The only Prisma-Blitz integration is the blitz db
cli command. You can use anything you want, such as Mongo, TypeORM, etc.
- Open
db/schema.prisma
and add the following:
model Project {
id Int @default(autoincrement()) @id
name String
tasks Task[]
}
model Task {
id Int @default(autoincrement()) @id
name String
project Project @relation(fields: [projectId], references: [id])
projectId Int
}
- Run
blitz db migrate
- If this fails, you need to change the
DATABASE_URL
value in.env
to whatever is required by your Postgres installation.
- If this fails, you need to change the
CRUD = create, read, update, delete
- Run
blitz generate all project
to generate fully working queries, mutations, and pages - Open http://localhost:3000/projects to see the default project list page
- Explore the generated pages and view, create, update, and delete projects.
Blitz.js pages are exactly the same as Next.js pages. If you need, read the Next.js Page documentation
- Unlike Next.js, you can have many
pages/
folders nested insideapp/
. This way pages can be organized neatly, especially for larger projects. Like this:app/pages/about.tsx
app/projects/pages/projects/index.tsx
app/tasks/pages/projects/[projectId]/tasks/[id].tsx
- All React components inside a
pages/
folder are accessible at a URL corresponding to its path insidepages/
. Sopages/about.tsx
will be atlocalhost:3000/about
.
The Next.js router APIs are all exported from the blitz
package: useRouter()
, withRouter()
, and Router
. If you need, read the Next.js Router documentation.
Blitz queries and mutations are plain, asynchronous Javascript functions that always run on the server.
We automatically alias the root of your project, so import db from 'db'
is importing <project_root>/db/index.ts
Example Query:
// app/products/queries/getProduct.tsx
import db, {FindOneProductArgs} from 'db'
export default async function getProduct(args: FindOneProductArgs) {
// Can do any pre-processing or event triggers here
const product = await db.product.findOne(args)
// Can do any post-processing or event triggers here
return product
}
Example Mutation:
// app/products/mutations/createProduct.tsx
import db, {ProductCreateArgs} from 'db'
export default async function createProduct(args: ProductCreateArgs) {
// Can do any pre-processing or event triggers here
const product = await db.product.create(args)
// Can do any post-processing or event triggers here
return product
}
Blitz provides a useQuery
hook, which is built on react-query
. The first argument is a query function. The second argument is the input to the query function. The third argument is any valid react-query configuration item.
At build time, the direct function import is swapped out for a function that executes a network call to run the query serverside.
React Concurrent Mode is enabled by default for Blitz apps. So the <Suspense>
component is used for loading states and <ErrorBoundary>
is used to display errors. If you need, you can read the React Concurrent Mode Docs.
import {Suspense} from 'react'
import {useRouter, useQuery} from 'blitz'
import getProduct from 'app/products/queries/getProduct'
import ErrorBoundary from 'app/components/ErrorBoundary'
function Product() {
const router = useRouter()
const id = parseInt(router.query.id as string)
const [product] = useQuery(getProduct, {where: {id}})
return <div>{product.name}</div>
}
export default function () {
return (
<div>
<ErrorBoundary fallback={(error) => <div>Error: {JSON.stringify(error)}</div>}>
<Suspense fallback={<div>Loading...</div>}>
<Product />
</Suspense>
</ErrorBoundary>
</div>
)
}
In getStaticProps
, a query function can be called directly without useQuery
import getProduct from '/app/products/queries/getProduct'
export const getStaticProps = async (context) => {
const product = await getProduct({where: {id: context.params?.id}})
return {props: {product}}
}
export default function ({product}) {
return <div>{product.name}</div>
}
In getServerSideProps
, pass a query function to ssrQuery
which will ensure appropriate middleware is run before/after your query function.
import {ssrQuery} from 'blitz'
import getProduct from '/app/products/queries/getProduct'
export const getServerSideProps = async ({params, req, res}) => {
const product = await ssrQuery(getProduct, {where: {id: params.id}}, {req, res}))
return {props: {product}}
}
export default function({product}) {
return <div>{product.name}</div>
}
For more details, read the comprehensive Query & Mutation Usage Issue
Mutations are called directly, like a regular asynchronous function.
At build time, the direct function import is swapped out for a function that executes a network call to run the mutation server-side.
import {useQuery} from 'blitz'
import getProduct from '/app/products/queries/getProduct'
import updateProduct from '/app/products/mutations/updateProduct'
function (props) {
const [product] = useQuery(getProduct, {where: {id: props.id}})
return (
<Formik
initialValues={product}
onSubmit={async values => {
try {
const product = await updateProduct(values)
} catch (error) {
alert('Error saving product')
}
}}>
{/* ... */}
</Formik>
)
}
For more details, read the comprehensive Query & Mutation Usage Issue
Blitz.js custom API routes are exactly the same as Next.js custom API routes. If you need, read the Next.js API route documentation
- Unlike Next.js, your
api/
folder must be a sibling ofpages/
instead of being nested inside. - All React components inside an
api/
folder are accessible at a URL corresponding to it's path insideapi/
. Soapp/projects/api/webhook.tsx
will be atlocalhost:3000/api/webhook
.
Blitz uses the blitz.config.js
config file at the root of your project. This is exactly the same as next.config.js
. Read the Next.js docs on customizing webpack.
- You need a production Postgres database. It's easy to set this up on Digital Ocean.
- For deploying serverless, you also need a connection pool. This is also relatively easy to set up on Digital Ocean.
- Read the Digitial Ocean docs on setting up your connection pool
- Ensure you set your "Pool Mode" to be "Session" instead of "Transaction" (because of a bug in Prisma)
- You need your entire database connection string. If you need, read the Prisma docs on this.
- If deploying to serverless with a connection pool, make sure you get the connection string to your connection pool, not directly to the DB.
- You need to change the defined datasource in
db/schema.prisma
from SQLite to Postgres
Assuming you already have a Zeit account and the now
cli installed, you can do the following:
- Add your DB url as a secret environment variable by running
now secrets add @database-url "DATABASE_CONNECTION_STRING"
- Add a
now.json
at your project root with
{
"env": {
"DATABASE_URL": "@database-url"
},
"build": {
"env": {
"DATABASE_URL": "@database-url"
}
}
}
- Run
now
Once working and deployed to production, your app should be very stable because it’s running Next.js which is already battle-tested.
You can deploy a Blitz app like a regular Node or Express project.
blitz start --production
will start your app in production mode. Make sure you provide the DATABASE_URL
environment variable for your production database.
Generate a new blitz project at <current_folder>./NAME
Start your app in development mode
Start your app in production mode
Run any needed migrations via Prisma 2 and generate Prisma Client
Will introspect the database defined in db/schema.prisma
and automatically generate a complete schema.prisma
file for you. Lastly, it'll generate Prisma Client.
Open the Prisma Studio UI at http://localhost:5555 so you can easily see and change data in your database.
Generate different types of files for a model. Your model input can be singular or plural, but the generated files will be the same in both cases.
Start a Node.js REPL that's preloaded with your db
object and all your queries and mutations. This is awesome for quickly trying your code without running the app!
- Read the Architecture RFC for more details on the architecture, our decision making, and how queries/mutations work under the hood
- Read the File Structure & Routing RFC for more details about the file structure and routing conventions.
- View an example Blitz app at
examples/store
Here's the list of big things that are currently missing from Blitz but are a top priority for us:
- A real Blitzjs.com website and documentation
- Translated documentation. If you're interested in helping, comment in this issue.
- Authentication
- Authorization (use auth rules both on server and client)
- Model validation (use model validation both on server and client)
- React-Native support
- GUI for folks who prefer that over CLIs
- ... and tons more 🙂
- Does Blitz support vanilla Javascript? Yes, but
blitz new
generates all Typescript files right now. You can add new files with JS and/or convert the generated files to JS. There's an open issue for generating vanilla JS files that needs help. - Will you support other ESLint configs for the
blitz new
app? Yes, there's an issue for this
Blitz is just getting started, and it's going to take an entire community to bring it to fruition!
How you can help:
- Tell others about Blitz
- Report bugs by opening an issue here on GitHub
- Send us feedback in the Blitz slack.
- Contribute code. We have a lot of issues that are ready to work on! Start by reading The Contributing Guide. Let us know if you need help.
- Any way you want! We totally appreciate any type of contribution, such as documentation, videos, blog posts, etc. If you have a crazy idea, feel free to run it past us in Slack! :)
- Sponsorships & donations
That's all for now. We hope to see you in the Blitz slack community!