1. What is Blitz
2. What are the core features
3. What are our plans for Blitz
4. What are we working on right now
Blitz is a Fullstack React Framework
Blitz is a Fullstack React Framework
✨ Inspired by Ruby on Rails
Blitz is a Fullstack React Framework
✨ Inspired by Ruby on Rails
✨ Built on top of Next.js
Blitz is a Fullstack React Framework
✨ Inspired by Ruby on Rails
✨ Built on top of Next.js
✨ Has Prisma by default
Blitz is a Fullstack React Framework
✨ Inspired by Ruby on Rails
✨ Built on top of Next.js
✨ Has Prisma by default
✨ Batteries-included framework
One thing to:
- Develop
- Deploy
- Think about
✨ Blitz abstracts the API into a build step
✨ Blitz abstracts the API into a build step
✨ It swaps the import with an HTTP call
✨ Blitz abstracts the API into a build step
✨ It swaps the import with an HTTP call
✨ Blitz resolvers: queries and mutations
✨ Blitz abstracts the API into a build step
✨ It swaps the import with an HTTP call
✨ Blitz resolvers: queries and mutations
✨ You can still add your own API
// app/products/queries/getProduct.ts
import db from "db"
import * as z from "zod"
const GetProject = z.object({
id: z.number(),
})
export default async function getProject(
input: z.infer<typeof GetProject>,
) {
const data = GetProject.parse(input)
const project = await db.project.findOne({ where: { id: data.id } })
return project
}
import { Suspense } from "react"
import { useQuery, useRouter, useParam } from "blitz"
import getProject from "app/projects/queries/getProject"
function Project() {
const router = useRouter()
const projectId = useParam("projectId", "number")
const [project] = useQuery(getProject, { where: { id: projectId } })
return <div>{project.name}</div>
}
function ProjectPage() {
return (
<Suspense fallback={<div>Loading...</div>}>
<Project />
</Suspense>
)
}
export default ProjectPage
// app/products/mutations/createProduct.tsx
import db from "db"
import * as z from "zod"
const CreateProject = z
.object({
name: z.string(),
})
export default async function createProject(
input: z.infer<typeof CreateProject>,
) {
const data = CreateProject.parse(input)
const project = await db.project.create({ data })
return project
}
import {useMutation} from 'blitz'
import updateProject from 'app/projects/mutations/updateProject'
function (props) {
const [updateProjectMutation] = useMutation(updateProject)
return (
<Formik
onSubmit={async values => {
try {
const project = await updateProjectMutation(values)
} catch (error) {
alert('Error saving project')
}
}}>
{/* ... */}
</Formik>
)
}
✨ New Blitz apps have auth
setup by default
✨ You can sign up and
login instantly
✨ New Blitz apps have auth
setup by default
✨ There's Passport.js adapter
for 3rd party login
✨ You can sign up and
login instantly
✨ New Blitz apps have auth
setup by default
singup mutation example
query with auth example
// app/auth/mutations/signup.ts
import { resolver, SecurePassword } from "blitz"
import db from "db"
import { Signup } from "app/auth/validations"
import { Role } from "types"
export default resolver.pipe(resolver.zod(Signup), async ({ email, password }, ctx) => {
const hashedPassword = await SecurePassword.hash(password.trim())
const user = await db.user.create({
data: { email: email.toLowerCase().trim(), hashedPassword, role: "USER" },
select: { id: true, name: true, email: true, role: true },
})
await ctx.session.$create({ userId: user.id, role: user.role as Role })
return user
})
singup mutation example
query with auth example
// app/auth/mutations/signup.ts
import { resolver, SecurePassword } from "blitz"
import db from "db"
import { Signup } from "app/auth/validations"
import { Role } from "types"
export default resolver.pipe(resolver.zod(Signup), async ({ email, password }, ctx) => {
const hashedPassword = await SecurePassword.hash(password.trim())
const user = await db.user.create({
data: { email: email.toLowerCase().trim(), hashedPassword, role: "USER" },
select: { id: true, name: true, email: true, role: true },
})
await ctx.session.$create({ userId: user.id, role: user.role as Role })
return user
})
singup mutation example
query with auth example
// app/auth/mutations/signup.ts
import { resolver, SecurePassword } from "blitz"
import db from "db"
import { Signup } from "app/auth/validations"
import { Role } from "types"
export default resolver.pipe(resolver.zod(Signup), async ({ email, password }, ctx) => {
const hashedPassword = await SecurePassword.hash(password.trim())
const user = await db.user.create({
data: { email: email.toLowerCase().trim(), hashedPassword, role: "USER" },
select: { id: true, name: true, email: true, role: true },
})
await ctx.session.$create({ userId: user.id, role: user.role as Role })
return user
})
singup mutation example
query with auth example
// app/auth/mutations/signup.ts
import { resolver, SecurePassword } from "blitz"
import db from "db"
import { Signup } from "app/auth/validations"
import { Role } from "types"
export default resolver.pipe(resolver.zod(Signup), async ({ email, password }, ctx) => {
const hashedPassword = await SecurePassword.hash(password.trim())
const user = await db.user.create({
data: { email: email.toLowerCase().trim(), hashedPassword, role: "USER" },
select: { id: true, name: true, email: true, role: true },
})
await ctx.session.$create({ userId: user.id, role: user.role as Role })
return user
})
singup mutation example
query with auth example
// app/products/queries/getProduct.ts
import {Ctx} from "blitz"
import db from "db"
import * as z from "zod"
const GetProject = z.object({
id: z.number(),
})
export default async function getProject(
input: z.infer<typeof GetProject>,
ctx: Ctx
) {
const data = GetProject.parse(input)
ctx.session.$authorize(),
const project = await db.project.findOne({ where: { id: data.id } })
return project
}
singup mutation example
query with auth example
// app/products/queries/getProduct.tsx
import {Ctx} from "blitz"
import db from "db"
import * as z from "zod"
const GetProject = z.object({
id: z.number(),
})
export default async function getProject(
input: z.infer<typeof GetProject>,
ctx: Ctx
) {
const data = GetProject.parse(input)
ctx.session.$authorize(),
const project = await db.project.findOne({ where: { id: data.id } })
return project
}
app/pages/projects/[projectId]/edit.tsx
app/pages/projects/[projectId].tsx
app/pages/projects/index.tsx
app/pages/projects/new.tsx
app/projects/components/ProjectForm.tsx
app/projects/queries/getProject.ts
app/projects/queries/getProjects.ts
app/projects/mutations/createProject.ts
app/projects/mutations/deleteProject.ts
app/projects/mutations/updateProject.ts
will generate the following files:
blitz generate all project
> blitz install tailwind
✅ Installed 2 dependencies
✅ Successfully created postcss.config.js, tailwind.config.js
✅ Successfully created app/styles/button.css, app/styles/index.css
✅ Modified 1 file: app/pages/_app.tsx
🎉 The recipe for Tailwind CSS completed successfully!
Its functionality is now fully configured in your Blitz app.
// app/pages/products/[productId].tsx
export default function ProductsPage() { ... }
// app/pages/products/index.tsx
import { Link, Routes } from "blitz"
export default function ProductsList() {
return (
// ...
<Link href={Routes.ProductsPage({ productId: 123 })} />
// ...instead of <Link href={`/products/${123}`} />
)
}
npm i -g blitz
blitz new my-new-blitz-project
(and fullstack web development 😎)
Blitz framework 🔜 framework-agnostic toolkit
✨ Nearly 100,000 Blitz projects have been created
✨ We recently passed the 10,000 Github Stars milestone
✨ People tell us it makes them 5-10x more productive
➡ Growth has stagnated in 2021
➡ The Next.js fork has hurt adoption
➡ We see a huge potential in a standalone toolkit
✨ Preserve the DX and features we currently have
✨ Preserve the DX and features we currently have
✨ Make it effortless for millions more developers to benefit from Blitz
✨ Preserve the DX and features we currently have
✨ Make it effortless for millions more developers to benefit from Blitz
✨ Decouple Blitz from any specific framework
✨ Preserve the DX and features we currently have
✨ Make it effortless for millions more developers to benefit from Blitz
✨ Decouple Blitz from any specific framework
✨ Enable us to ship features without the burden of maintaining the Next.js fork
✨ The current blitz codebase may be moved to a different
repo, but we will continue to make fixes releases as needed
✨ The current blitz codebase may be moved to a different
repo, but we will continue to make fixes releases as needed
✨ We are working to make the new setup as close as possible to the current setup
✨ The current blitz codebase may be moved to a different
repo, but we will continue to make releases as needed
✨ We are working to make the new setup as close as possible to the current setup
✨ We'll strive to make the migration to the Blitz toolkit as seamless as possible
const {setupClient, gSSP, gSP, api, BlitzServer} = setupServer({
plugins: [
AuthPlugin({
cookiePrefix: 'my-app',
// choose one of the following
storage: AuthPlugin.storage.prisma(db),
storage: AuthPlugin.storage.redis({url: '...'}),
storage: {
getSession: (stuff) => redis.get(stuff),
createSession: ...,
}
}),
ZeroApiPlugin({
middlewares: [],
queries: [ /* resolvers here */ ],
mutations: []
}),
FileUploadPlugin({
s3: {...}
})
],
})
const {setupClient, gSSP, gSP, api, BlitzServer} = setupServer({
plugins: [
AuthPlugin({
cookiePrefix: 'my-app',
// choose one of the following
storage: AuthPlugin.storage.prisma(db),
storage: AuthPlugin.storage.redis({url: '...'}),
storage: {
getSession: (stuff) => redis.get(stuff),
createSession: ...,
}
}),
ZeroApiPlugin({
middlewares: [],
queries: [ /* resolvers here */ ],
mutations: []
}),
FileUploadPlugin({
s3: {...}
})
],
})
export const {
useQuery,
useQueries,
useInfiniteQuery,
useMutation,
queryClient,
useSession,
withBlitz,
} = setupClient<BlitzServer>({
plugins: [
AuthPlugin(),
ZeroApiPlugin(),
],
})
interface ClientPlugin {
events: {
onSessionCreate?
onSessionDestroy?
},
middleware: {
beforeHttpRequest?
beforeHttpResponse?
},
exports?
withProvider?
}
Goals:
import {resolver, NotFoundError} from "blitz"
import db from "db"
import {z} from "zod"
const GetProject = z.object({
id: z.number()
})
export default resolver.pipe(
resolver.zod(GetProject),
resolver.authorize(),
async ({id}) => {
const project = await db.project.findFirst({where: {id}})
if (!project) throw new NotFoundError()
return project
}
)
import {useQuery, useMutation} from 'blitz.client'
const [project] = useQuery("getProject", { id: 1 });
const [createProjectMutation] = useMutation('createProject')
import { setupServer, sessionMiddleware } from "@blitzjs/next"
import * as projectQueries from "app/projects/queries"
export const { api, gSSP, gSP, Server } = setupServer({
plugins: [
ZeroApiPlugin({
queries: [ ...projectQueries ],
}),
]
})
import {useQuery, useMutation} from 'blitz.client'
const [project] = useQuery("getProject", { id: 1 });
const [createProjectMutation] = useMutation('createProject')
import { setupServer, sessionMiddleware } from "@blitzjs/next"
import * as projectQueries from "app/projects/queries"
export const { api, gSSP, gSP, Server } = setupServer({
plugins: [
ZeroApiPlugin({
queries: [ ...projectQueries ],
}),
]
})
Note: We are strongly considering keeping the current magical import for resolvers
🔨 Plugin system design
🔨 Extracting authN & authZ from Blitz
🔨 Building standalone packages
➡️ https://blitzjs.com/
➡️ https://github.com/blitz-js/blitz