Idea to prod in 34 minutes with v0
Ever come up with a great idea in a quick chat with a coworker? How often do you follow through on shipping those things?
Sometimes you send the Slack messages to the right team, create the Jira tickets, and get the ball rolling. A few weeks/months later, your new internal tool is live.
But sometimes, even the best ideas die after that chat.
I was chatting with Matt Jared at a recent Vercel offsite and realized we could detect client-side rendering with a few screenshots & the AI SDK.
So I thought:
I have 30 minutes before my next event — why not go try to buy a domain and ship it?
Here's what we shipped (link):
Launch Timeline
Bought the domain
1:04 PM
Logged into Vercel and bought isthiscsr.com
Initial commit
1:22 PM
Deployed a basic Next.js template to Vercel and assigned the domain
Tweaked the design with v0
1:24 PM
Used v0 to get a first draft of the design based on the Google homepage
Shipped to prod
1:38 PM
Had a rough working version before my 1:45 PM departure
With the great DX of the AI SDK, v0 filling the blank page, and Cursor helping me with Browserbase/Playwright syntax, this project was up and running in no time.
'use server'
import { chromium } from "playwright"
import { put } from '@vercel/blob';
export async function getImages(url: string) {
const browser = await chromium.connectOverCDP(`wss://connect.browserbase.com?apiKey=${process.env.BROWSERBASE_API_KEY}`)
const [defaultContext, secondContext] = await Promise.all([
browser.contexts()[0],
browser.newContext({ javaScriptEnabled: false })
])
const [page, secondPage] = await Promise.all([
defaultContext.pages()[0],
secondContext.newPage()
])
// Set the same viewport size for both pages to latest iPhone size
const viewportSize = { width: 428, height: 926 }; // iPhone 14 Pro Max size
await Promise.all([
page.setViewportSize(viewportSize),
secondPage.setViewportSize(viewportSize)
]);
console.log('Navigating to URL:', url)
const [jsScreenshot, noJsScreenshot] = await Promise.all([
page.goto(url as string, { timeout: 60000 }).then(() => page.waitForTimeout(750)).then(() => page.screenshot({ fullPage: false })),
secondPage.goto(url as string, { timeout: 60000 }).then(() => secondPage.waitForTimeout(750)).then(() => secondPage.screenshot({ fullPage: false }))
])
const [blobUrl, secondBlobUrl] = await Promise.all([
put(`${url}-screenshot-JS.png`, jsScreenshot, {
access: 'public',
contentType: 'image/png'
}),
put(`${url}-screenshot-noJS.png`, noJsScreenshot, {
access: 'public',
contentType: 'image/png'
})
])
console.log('Screenshot URLs:', blobUrl.url, secondBlobUrl.url)
await browser.close()
return {
noJS: secondBlobUrl.url,
js: blobUrl.url
}
}
While it's a small application, in the past I don't think I would have taken the time to write these 1,400 lines of code for such a niche use case.
is-it-csr git:(main) cloc . --exclude-dir=node_modules,.next --exclude-lang=JSON
32 text files.
30 unique files.
11 files ignored.
github.com/AlDanial/cloc v 2.02 T=0.01 s (2423.2 files/s, 157990.3 lines/s)
-------------------------------------------------------------------------------
Language files blank comment code
-------------------------------------------------------------------------------
TypeScript 21 135 70 1267
CSS 1 9 0 95
Markdown 1 13 0 23
JavaScript 2 2 4 12
-------------------------------------------------------------------------------
SUM: 25 159 74 1397
-------------------------------------------------------------------------------
AI is dramatically reducing friction and the cost of production for software. We're not far away from a world where every niche has vertical software built specifically for their use case. This doesn't mean engineering jobs are at risk. In fact, it likely only means there will be more of them.
When your friend comes to you with "a random idea for an app", you build it now instead of telling them how hard it is.
And that's a good thing.
p.s. — the little timeline component in this post was made with v0 too