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

Stay up to date

Don't miss my next post — get it delivered straight to your inbox.