Mike Cann's avatar
Mike Cann
5 months ago

Replit + Convex: Ship a Mobile App to TestFlight

Wow. Just wow. I don't normally gush, but this genuinely has me excited.

Replit has been knocking it out of the park lately: rapid improvements to its autonomous agent (versions two and three), self-contained hosting, and now the ability to publish mobile apps directly to the App Store. That combination makes it one of the better AI mobile app builders around for vibing out your next app.

It had been a while since I last checked Replit out, so I wanted to see whether I could get a Convex project running inside it. Turns out you can, easily. I was surprised how fast I got a working app onto the App Store, powered by real-time Convex data instead of the database Replit bakes in by default.

I think this idea-to-App-Store pipeline is a big deal for anyone who's wanted to build mobile apps but been put off by how complex mobile development gets, myself included. Here's what's involved in taking an app from idea to the App Store using Replit as an AI mobile app builder, with Convex as the backend.

Setting up Replit and starting the build

To get started, you need a Replit account, and specifically a paid one. I used Replit Core, at $20 a month, because you need credits to run the agent and to run Convex in a background task.

Once you're in, click to build an app, select "mobile app," and write a prompt. Mine was: "Please build a beautiful mobile app for tracking daily habits. I would like to store all my data in a Convex database." It matters that the prompt says "mobile app" and "Convex database" explicitly. Leave out "Convex" and Replit defaults to its own built-in Postgres database instead.

Start the build, and while it's constructing the app, you need to connect Convex to the project. Replit doesn't have a direct Convex integration yet, though I'm hoping to change that (more on that at the end). For now you open a shell window and run npx convex dev. It asks to install the CLI, prompts you to log into your account through the browser, and then lets you create a new project. I called mine replit-habits and pointed it at the cloud.

While that's running, it's worth a quick tour of the updated Replit UI. The agent sits in a big bar on the left, similar to Bolt or Lovable, with your files on the right. The scaffold includes Drizzle by default, an ORM for Postgres, which you don't need because you're using Convex instead. Once the agent finishes generating the schema, you can see it wrote a habits table and a completions table, with indexes already added. That lines up with how Convex expects you to define your schema up front.

1import { defineSchema, defineTable } from "convex/server";
2import { v } from "convex/values";
3
4export default defineSchema({
5  habits: defineTable({
6    name: v.string(),
7    icon: v.string(),
8    color: v.string(),
9    frequency: v.array(v.number()),
10    createdAt: v.number(),
11    archived: v.boolean(),
12  }),
13  completions: defineTable({
14    habitId: v.id("habits"),
15    date: v.string(),
16    completedAt: v.number(),
17  }).index("by_habit", ["habitId"])
18    .index("by_date", ["date"])
19    .index("by_habit_date", ["habitId", "date"]),
20});
21

Replit also gives you the option of plan mode instead of build mode. For a demo, moving straight to build is faster. For anything real, though, I'd recommend plan mode so the agent thinks through the problem before it starts writing code.

Wiring up the Convex connection

Once the agent finishes, it tells you to go create a Convex account, not realizing you're already running one locally. Rather than explain that to the agent, the simpler fix is to copy the Convex URL out of the dev process's .env.local file. Paste it in when the agent asks for the public Convex URL.

I love that Replit shows you the cost of each step as you go. Hovering over a completed step showed $1.91 for about six minutes of agent work. A small thing, but it's the kind of transparency that makes iterating with an agent feel less like a black box.

After that step finished, the app preview broke with a generic "something went wrong" message. It hinted that I might have forgotten to run npx convex dev or npx convex deploy. I'd seen this exact failure before. The dev process had started before package.json was fully built, so it never picked up the right config. Canceling the dev process and starting it again fixed it. Once it restarted, it created the indexes, uploaded the functions, and reloading the preview brought the app up cleanly.

From there, Replit walked through the app in its own preview to confirm everything worked. That's a genuinely useful feature. You can watch its reasoning as it clicks through the UI it just built.

Testing real-time sync across web and native

With the app running, I added a habit. I picked an icon, named it "Drink water," saved it, and watched it show up.

Because this is an Expo app, the preview panel includes a QR code. Scanning it with Expo Go on my phone downloaded and bundled the project as a native app, and "Drink water" appeared there too. Tapping it to check it off updated instantly. Switching back to the web preview and adding a new task, "subscribe," with its own emoji, it appeared on the phone immediately as well. That's Convex's reactive queries at work. Subscriptions update automatically whenever the underlying data changes, so there's no polling or manual refresh logic to write on either the web or native client.

Publishing the web build

Once the app itself worked, the next step was publishing. Clicking "ready to publish" opens Replit's publish flow, which had already generated an app icon and some marketing images. It assigns a free domain (mine was habit-tracker-convex.replit.app), though you can buy a custom one through Replit if you want.

The default deployment type is "Autoscale," which assumes you need a server. I switched it to "Static Pages" instead, because there's no Express backend to run here. All the server-side logic lives in Convex.

In the build command field, I removed the default and replaced it with:

1npx convex deploy && npx expo export --platform web
2

npx convex deploy pushes the code in the convex/ directory to production, and npx expo export builds the Expo project for the web. I set the output directory to dist, since that's where the Expo web export lands, and told Replit that's where the site lives.

For Replit's build process to push Convex code, it needs its own credentials. In the Convex dashboard, I switched to the project's production deployment (mine was named "Rosie Otter 666" by Convex's auto-generated naming) and went to Settings → Deploy Keys to generate a production deploy key. I called it "replit" and copied it into Replit's Deployment Secrets as CONVEX_DEPLOYMENT_KEY.

That alone isn't quite enough, though, because the web build and any native mobile builds need to agree on which Convex deployment they're targeting. The web build correctly points at production once the deploy key is set, but mobile builds can still default to the development deployment unless you tell them otherwise. Convex handles this with environment variables scoped per file. I duplicated .env.local into .env.production.local, then changed the deployment value inside it from the development deployment ("Groovy Squid") to the production one ("Rosie Otter 666").

With that in place, clicking Publish ran through provisioning, a security scan, the build, bundling, and promotion. Opening the published site showed an empty app, since it was now correctly pointing at production instead of the dev data I'd been testing against. Adding a habit called "prod" confirmed it. The production and development environments were now cleanly separated, exactly how Convex expects you to manage dev versus prod.

Shipping to TestFlight

The last piece was getting a native build onto TestFlight. Replit has an embedded Expo/EAS flow for this. Clicking the publish button opens an Expo launch panel inside Replit itself. I picked a project name (mine was "Bloom") and signed in with my Apple ID and password. That does require an Apple Developer Program account, which runs $99 a year. Replit claims the sign-in is verified locally rather than transmitted anywhere.

Creating and preparing the app is normally automatic on a first run, including generating the Apple distribution certificate. I hit one snag. Apple caps you at two active distribution certificates, and I'd already hit that limit, so I had to revoke an old one before Replit could generate a new provisioning profile. Once that resolved, I clicked "Ready to Launch," which kicked off Expo's EAS, its own CI build system. That builds the native binary and pushes it to the App Store. Replit estimated about 45 minutes for that step.

While it built, I got an email inviting me to the app on TestFlight. Installing it and opening it showed the production data I'd added earlier. Making a change in the Convex dashboard updated the app on my phone instantly, the same real-time behavior I'd seen between the web preview and Expo Go earlier.

Getting from TestFlight to the actual App Store still requires Apple's review process, which can take anywhere from a few days to a week. I didn't run that step for this video, but submitting for review from there is only a few clicks in Apple's own dashboard.

Takeaways

I'm honestly amazed at how fast this AI mobile app builder got me to a working mobile app, and I did the whole thing on Windows, without a Mac. Replit also has its own mobile app, so in principle you could keep iterating on a project from your phone.

The one thing that would make this meaningfully better is a native Convex integration inside Replit, instead of routing around the built-in Postgres database by hand. I'm going to push for that internally. Ideally Replit would offer Convex as a first-class option from the start, maybe even with the Convex dashboard embedded directly in the Replit interface.

Real-time data that just works across web and native, shipped without touching a backend server once, that's the part I keep coming back to.

Build in minutes, scale forever.

Convex is the backend platform with everything you need to build your full-stack AI project. Cloud functions, a database, file storage, scheduling, workflow, vector search, and realtime updates fit together seamlessly.

Get started