Lessons From Building Products for Overseas Markets
Claude Code has gotten really good lately, and a lot of people now have a shot at building their own products (I’ve collected some of my own non-coding uses of it in My Claude Code Practices). I’ve built all sorts of things myself, and I want to share the tech stack I commonly use along with the various SaaS platforms involved, as a reference for everyone.
Static Websites
A static website here means a purely display-oriented page that’s simply hosted online, without back-end features like a database. This is very common for landing pages or personal blogs, and it’s also the simplest kind of requirement—one you can implement at essentially zero cost.
Tech Stack
Personally I’m a fan of the Next.js and Astro ecosystems; they’re relatively simple to develop with. I use Astro for content sites, and Next.js for things with more complex interactivity. Both are open-source frameworks and free to use.
Hosting Platforms
The platforms I commonly use are Vercel and Cloudflare Pages.
- Cost: For early-stage personal projects, these platforms are almost entirely free.
- Vercel: The Hobby free plan offers 1 million function invocations per month and about 4 CPU-hours of compute (personal, non-commercial use only).
- Cloudflare Pages: The free plan offers 500 builds per month, with unlimited bandwidth and requests.
- ICP filing: No need to go through the cumbersome domestic Alibaba Cloud ICP filing process.
- Access speed: Cloudflare’s CDN is very powerful, so even without an ICP filing, users in mainland China can usually still access your site normally.
- Domains: Both platforms support custom domains, and this feature is entirely free.
Buying a Domain
For domains, I’d suggest buying from GoDaddy or Namecheap; these are the two most widely used platforms right now. Cloudflare Registrar can now register domains too, and its biggest selling point is that it sells at cost (the registry wholesale price + ICANN’s roughly $0.18 fee) with no markup, and renewals don’t go up in price either. If your domain is already hosted on Cloudflare, it’s very convenient.
Traffic Analytics
Google Analytics
I recommend using Google Analytics (the standard GA4 version is entirely free for the vast majority of sites). With it you can clearly see where your traffic comes from and how it’s distributed—for example, which country or region’s visitors viewed which of your pages. Its analytics capabilities are very powerful.

UTM Tags
If you’re running promotions across multiple channels (e.g. posting on Twitter, running ads, sharing in different communities) and want to know how much traffic each channel brings in, you’ll need UTM tags. The principle is simple: you append a string of parameters to the link, and once Google Analytics recognizes them, it can separate out the sources for you.
A few commonly used parameters:
utm_source: The traffic source, e.g.twitter,reddit,newsletter.utm_medium: The medium type, e.g.social,cpc(paid clicks),email.utm_campaign: The campaign name, e.g. a specific promotionlaunch_2026.
The resulting link looks roughly like this:
https://yoursite.com/?utm_source=twitter&utm_medium=social&utm_campaign=launch_2026
Send this parameterized link out to the corresponding channel, and afterward you can view each channel’s traffic and conversion performance in Google Analytics broken down by source/medium/campaign, helping you judge which channel is worth investing in. Assembling parameters by hand is error-prone, so you can use Google’s official Campaign URL Builder to generate them. I’ve written a dedicated piece on the full meaning of UTM’s five parameters, naming conventions, and a dozen or so real examples in Using UTM Tags to Analyze Traffic Sources; take a look if you want to go deeper.
Media Storage (Image Hosting)
If your site has a lot of images or videos, bundling them directly into the project leads to a bloated build size and hurts loading. In that case you should put the media files separately into object storage and distribute them via a CDN. There are two layers to discuss here: the underlying file storage, and the image processing on top.
Object Storage: R2
For the underlying storage I recommend Cloudflare’s R2; it’s the place to store your raw files:
- S3-compatible: Your existing S3 SDKs and tools can basically migrate over seamlessly, with no extra learning curve.
- No egress fees: This is its biggest advantage over AWS S3—egress (outbound traffic) is entirely free, which is especially cost-effective for read-heavy use cases like image hosting/CDN.
- A generous free tier: 10GB of storage, 1 million Class A write operations, and 10 million Class B read operations per month—basically zero cost for getting a personal project off the ground.
- Custom domain support: You can serve files under your own domain, and read/write speeds are fast.
Image Processing and Delivery: Images
Storage alone isn’t enough. The front end often needs images at different sizes and in different formats for different spots (thumbnails, lists, detail pages, Retina screens). Generating them all ahead of time and storing each copy is both tedious and space-consuming. Cloudflare’s Images is designed to solve exactly this, and its core capability is image transforms:
- On-the-fly transforms: You store just one original image, and by adding parameters to the URL you can generate different versions in real time—e.g. adjusting width/height (
width/height), crop behavior (fit/crop), compression quality (quality), and so on. The result is cached on the CDN edge nodes, and subsequent visits hit the cache directly. - Automatic format selection: Based on the visitor’s browser support, it can automatically convert to more compact modern formats like WebP / AVIF, noticeably reducing image size and speeding up loading.
- Works with R2 or remote images: Transforms don’t require the image to be hosted on Images itself—images stored in R2, or even at some other remote address, can go straight through Images to be transformed and delivered.
- Pricing: Billed by “number of transforms + delivery volume,” with a free tier of 5,000 remote-image transforms per month, which is plenty to start.
For a concrete example, suppose you have an original image:
https://img.yoursite.com/photos/cat.jpg
Through Cloudflare’s transform URL (the format is /cdn-cgi/image/<params>/<original-image-url>), you can get different versions via different links, while the original is only ever stored once:
# A 200px thumbnail for lists, with quality compressed to 75
https://yoursite.com/cdn-cgi/image/width=200,quality=75/https://img.yoursite.com/photos/cat.jpg
# An 800px large image for detail pages, auto-converted to a more compact format (webp/avif)
https://yoursite.com/cdn-cgi/image/width=800,format=auto/https://img.yoursite.com/photos/cat.jpg
# A fixed 400x400 square avatar, cropped to fill without distortion
https://yoursite.com/cdn-cgi/image/width=400,height=400,fit=cover/https://img.yoursite.com/photos/cat.jpg
As you can see, you only need to change the parameters in the URL (width, height, quality, fit, format, etc.) to instantly get an image at the corresponding size/format. After the first visit, the result is cached on the CDN, and subsequent visits hit it directly. The front end just needs to assemble the right links per scenario—no need to generate and manage a pile of image files in advance.
In short: R2 handles storing the originals, Images handles transforming, compressing, and delivering the images on demand. Pairing the two gives you a complete, cheap image-hosting setup.
SEO Optimization
If you’re writing a blog, try to build your static site with Astro, because it’s very SEO-friendly (static pages, fast loading, and friendly to search-engine crawling). There are plenty of mature courses on SEO online; here I’ll split what I usually do into three parts: technical measures, backlinks, and relevant tools.
I should note up front that the most core thing is still the content itself. You just need to keep producing high-quality content, and search engines will crawl it automatically; as long as the content is solid, the odds of being indexed and discovered are high. Everything below is “supporting work” layered on top of the content.
Technical Measures
Most of this is one-time, fixed work—once it’s set up you basically don’t need to touch it again (Claude Code can handle it):
- Lay out the site structure, write
robots.txtand a sitemap, so search engines know which pages can be crawled and what pages the site has. - Submit the site to Google Search Console, where you submit your sitemap and check indexing status and search keyword performance.
- Configure a dedicated title and meta description for each page, plus Open Graph / Twitter Card tags (which determine the preview title and large image when a link is shared on platforms like X, Slack, etc.).
- Add Schema.org structured data (JSON-LD) to article pages, which gives you a chance at rich results in search (FAQ, star ratings, etc.) for a higher click-through rate.
- If you’re going multilingual/multi-region, remember to configure hreflang tags—this is a must-have for overseas sites.
Items 3 and 4 above, dropped into the page <head>, look roughly like this—essentially a fixed template you configure on every page (with Astro, just extract it into a component and pass props):
<!-- Basic SEO + social sharing preview -->
<title>Article Title - Site Name</title>
<meta name="description" content="A page summary of about 120 characters" />
<link rel="canonical" href="https://yoursite.com/blog/my-post/" />
<meta property="og:title" content="Article Title" />
<meta property="og:description" content="Page summary" />
<meta property="og:image" content="https://yoursite.com/og/my-post.png" />
<meta name="twitter:card" content="summary_large_image" />
<!-- JSON-LD structured data for the article page -->
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Article",
"headline": "Article Title",
"datePublished": "2026-06-09",
"author": { "@type": "Person", "name": "Your Name" }
}
</script>
Once it’s set up, use Google’s Rich Results Test to verify the structured data can be correctly recognized, then go to Search Console to submit the sitemap and get indexed.
Backlinks
Backlinks (i.e. other sites linking to you) are the hardest but also the most critical factor in a new site’s ranking. Good content alone isn’t enough—you also need others linking to you before search engines will consider your site to have authority. Things you can do at the starting stage:
- Submit your product/blog to relevant directory sites, listing sites, and platforms like Product Hunt.
- Share valuable content in relevant communities (Reddit, Hacker News, Zhihu, niche forums, etc.), naturally including a link.
- Write content that others are willing to cite on their own (tutorials, data, tools)—this is the healthiest source of backlinks.
Relevant Tools
For keyword research and competitor analysis, the tools I commonly use are Ahrefs and Semrush. You can check a keyword’s search volume and competitiveness, as well as which keywords competitors rank for—very useful when deciding “what to write.”

The official subscriptions for both tools are fairly pricey (easily hundreds of dollars a month). If it’s just a personal project, there are plenty of shared / mirror accounts on Taobao at a much lower price—buy a few days as needed or split a one-month plan, which is plenty to start.
Additionally, Google’s own Keyword Planner is free; although its data precision isn’t as good as the two above, it’s perfectly fine to start with.
Full Front-End/Back-End Applications
Websites with a complete front end and back end are generally fairly common among SaaS platforms. The biggest difference from the static websites mentioned earlier is that these have a complete back-end system—including a back-end server, a database, and so on—that provides data services to the front end.
This type involves more content. For the front-end part, you can refer to the Static Websites section. On the back-end side, there are roughly two technical routes:
The Serverless Route
In this model there’s no continuously running server sitting in the background. Whenever a request comes in from the front end, the system temporarily spins up a server to do the work, and shuts it down immediately once the task is done.
For language, TypeScript is the most convenient—the front end is already TS, so writing the back end in TS too unifies the whole stack, and paired with Vercel you can ship front end and back end together in one shot, sparing you the cost of switching back and forth between languages.
- Pros: Fairly cheap, billed entirely by usage. No charges when there are no requests.
- Cons: It doesn’t support long-running background tasks (e.g. wanting to spin up a thread that keeps doing something). If you really need to, you can consider periodic scheduling via a cron job.
- Common platforms:
- Cloudflare Workers: The free plan offers 100,000 requests per day, with a 10ms CPU cap per request.
- Vercel’s back end: Built on top of AWS Lambda.
- AWS’s native Lambda: A perpetual free tier of 1 million requests + 400,000 GB-seconds of compute per month, which never expires.
The Server Route
This is a fairly common approach: you typically build a Docker image and run it as a long-running service.
For language, I generally use Golang: it compiles to a single static binary, builds into a very lightweight Docker image, and has strong performance and concurrency—very well suited to running a long-lived service.
- Self-hosted server: Just find a server online and run the Docker image on it.
- Pros: The cheapest option, winning on low cost and control.
- Cons: The most operationally tedious—you have to worry about reverse proxies, scaling, and other chores yourself.
- Google Cloud Run: You just write a Dockerfile on GitHub, and every time the code updates it automatically rebuilds the image for you. Cloud Run supports both a pay-per-use mode (destroyed after running) and a long-running background mode.
- Free tier: About 2 million requests, 180,000 vCPU-seconds, and 360,000 GiB-seconds per month (in designated regions). The costs below are after deducting the free tier.
- Pay-per-use (CPU allocated only during requests): about $0.000024/vCPU-second for vCPU, about $0.0000025/GiB-second for memory, plus $0.40 per million requests. When there’s no traffic it scales to zero and incurs no charges at all—suitable for low-frequency or fluctuating-traffic scenarios.
- Long-running (CPU always allocated to the instance): lower unit prices (about $0.000018/vCPU-second for vCPU, about $0.0000020/GiB-second for memory) and no request fees, but billed by the instance’s total running time—a 1 vCPU / 512MB instance running 24/7 for a month is roughly on the order of $45–50. Suitable for services that need to stay resident and can’t tolerate cold starts.
- fly.io: Suitable for small apps just starting out. It handles scaling automatically, connects seamlessly with GitHub to form a pipeline, and comes with a built-in Grafana dashboard, making monitoring very convenient.
- Cost: It has now cancelled its free tier and switched to pure pay-as-you-go; for a small app, the practical minimum is roughly $5/month and up.
- Other platforms: You can also try products like AWS’s EKS.
- Cost: The control plane is billed at $0.10/hour (about $73/month), with nodes charged separately.
Overall, the main difference between these two routes is: one is serverless, and the other is a long-running server.
One thing to add: cloud providers like AWS, GCP, and Azure offer a sizable amount of credit “freebies” for early-stage projects and startups (easily several thousand to tens of thousands of dollars), and many don’t even require VC backing to apply directly. How to claim them, and which tiers have zero barriers, I’ve laid out specifically in Perks for Startups—they can save you quite a bit of real money at the starting stage.
API Contracts
As long as the front end and back end are separated, how to align the API is an unavoidable issue—the most annoying being those low-level bugs caused by fields and types not matching up between front and back end. How to solve it depends on two cases:
If you’re going all-in on TS, you actually don’t need OpenAPI at all. Both front end and back end are TypeScript, so just put the request/response type definitions into a shared package (both sides import the same types in a monorepo), share one set of types, change it in one place and both sides change together, and you’ll catch mismatches at compile time. In this case, layering OpenAPI on top is actually redundant.
If the back end is Golang (or another non-TS language), the front end and back end use different languages and can’t share types directly, and that’s when you need OpenAPI (formerly Swagger) as the “contract”: use a single description file to clearly define the API’s paths, parameters, and request/response structures, and have both front and back end follow it so things don’t drift.
My own practice is this pipeline:
- The back end writes APIs with the Go framework Huma, which can generate
openapi.jsondirectly from the Go code—no need to hand-write and hand-maintain that spec separately; change an endpoint and re-run it and it’s synced. - The front end then uses openapi-typescript to convert that
openapi.jsoninto TypeScript types, and paired with itsopenapi-fetchyou get a type-safe request client directly.
On the back-end side, writing an API with Huma looks roughly like this—inputs/outputs are ordinary Go structs, field constraints and examples are annotated directly with struct tags, and Huma generates the OpenAPI from these automatically and serves openapi.json at a fixed route:
package main
import (
"context"
"net/http"
"github.com/danielgtaylor/huma/v2"
"github.com/danielgtaylor/huma/v2/adapters/humago"
)
// Input: a path parameter "name", with validation and an example, all of which go into the OpenAPI
type GreetingInput struct {
Name string `path:"name" maxLength:"30" example:"world"`
}
// Output: the HTTP body is wrapped inside the Body field
type GreetingOutput struct {
Body struct {
Message string `json:"message" example:"Hello, world!"`
}
}
func main() {
mux := http.NewServeMux()
api := humago.New(mux, huma.DefaultConfig("My API", "1.0.0"))
// Register a GET endpoint; the handler is strongly typed: no manual parsing of inputs or outputs needed
huma.Get(api, "/greeting/{name}", func(ctx context.Context, in *GreetingInput) (*GreetingOutput, error) {
resp := &GreetingOutput{}
resp.Body.Message = "Hello, " + in.Name + "!"
return resp, nil
})
// After startup: openapi.json is automatically served at /openapi.json, with interactive docs at /docs
http.ListenAndServe(":8888", mux)
}
On the front end, this step is basically two lines—just re-run it whenever the API changes:
# Generate TS types from the openapi.json exported by the back end
npx openapi-typescript ./openapi.json -o ./src/api/schema.d.ts
# Then use openapi-fetch in your business code; paths, params, and return values are all type-safe end to end
# import createClient from "openapi-fetch";
# import type { paths } from "./api/schema";
# const api = createClient<paths>({ baseUrl: "https://api.yoursite.com" });
# const { data, error } = await api.GET("/users/{id}", { params: { path: { id } } });
On the Huma side, it serves openapi.json at a fixed route when the service starts (or via a single export command), and the front-end CI pulls this file and regenerates. Over this whole pipeline (Go code → openapi.json → type-safe front-end client), the moment the back end changes an endpoint, the front end regenerates, and all affected calls error out at compile time, essentially eliminating front-to-back integration bugs. As a bonus you also get free API documentation and an online debugging page, which makes integration testing very convenient.
If the back end is in a different language, or you need to generate more than just a TS client, you can switch to the more general openapi-generator, which supports dozens of languages and can generate both front-end SDKs and back-end skeletons.
Database and User Management
A back end basically can’t do without a database, and many scenarios also come with a set of user authentication. These two are often considered together; below I’ll split them into database and authentication.
Database
- Supabase: Based on PostgreSQL, and beyond the database itself it bundles a whole suite of back-end capabilities (auth, storage, etc.). It’s quick to get started with and a popular choice for getting a personal project off the ground.
- Cost: The free tier is enough to start a personal project—500MB of database, 1GB of file storage, and an auth allowance of 50,000 monthly active users (MAU) per month.
- Neon: A serverless PostgreSQL database, billed by usage and able to auto-suspend.
- Cost: The free plan offers 100 compute hours and about 5GB of storage per month, with mandatory scale-to-zero.
- AWS and Google Cloud: If you want a more formal, more robust solution, their managed PostgreSQL (AWS’s RDS, GCP’s Cloud SQL) is more solid. Unlike the “free to start” products above, these are billed by instance time—a small-spec entry tier is roughly on the order of $10–40 per month, more solid for running production but costing money from the start.
Authentication
For auth you can either use the database’s built-in solution or hand it off to a dedicated service:
- Supabase Auth: If you’re already using Supabase, it comes with built-in authentication, and you can host the entire auth logic right on it. It manages users and login state for you, with no need to integrate another service—very convenient.
- Cost: It follows the Supabase project—the free plan offers 50,000 monthly active users (MAU) per month; the Pro plan (from $25/month) includes 100,000 MAU, billed at about $0.00325/MAU beyond that.
- Clerk: A company dedicated to auth. Beyond back-end management, it even provides ready-made front-end login pages you can use directly.
- Cost: The free tier is 50,000 monthly active users (MAU/MRU) per application per month, after which the Pro plan starts at $25/month with usage-based billing.
Caching Services
Beyond the commonly used PostgreSQL database, a back end usually also makes use of a cache like Redis.
- Provided by cloud vendors: All the major cloud providers offer managed Redis (AWS’s ElastiCache, GCP’s Memorystore), billed by node spec/capacity and time, with a small spec running roughly $10–35 per month. You can also buy a server and set it up yourself, which is cheaper but requires you to handle ops.
- Upstash: A ready-made provider offering out-of-the-box Redis. It also provides a monitoring page so you can easily check read/write activity. It essentially packages Redis up nicely, making it more carefree to use.
- Cost: It has a free tier of 500,000 commands per month, 256MB of data, and the first 200GB of bandwidth per month.
Payments and Subscription Logic
If billing logic is involved, the default first choice is generally Stripe.
- Strengths: Their SDK is beautifully designed and very pleasant to use, whether for managing subscribers or handling payment logic.
- Service: Stripe’s overall service quality is very high—it’s a payment platform very well suited to programmers, and its reputation has always been good.
- Fees: No setup fee or monthly fee, with a per-transaction cut—2.9% + $0.30 per transaction for U.S. domestic cards, with additional cross-border and other fees for international cards.
AI Services
These days building an application basically can’t avoid AI capabilities. I’ll organize the commonly used services here by task type. The prices below were collected around June 2026; AI models iterate fast, so please defer to the official sites for specifics.
Text (LLMs)
Choose based on task complexity and what you need:
- Simple tasks (translation, summarization, classification, etc.):
- Want cheap: Chinese models like DeepSeek offer extremely high value for money and are also good with Chinese. The price is roughly on the order of $0.14 input / $0.28 output per million tokens, with an even lower price for cache hits.
- Want speed: Groq, with its in-house LPU inference chips, is blazingly fast (open-source models can often run at 500+ tokens/second) and also cheap. Note that it only hosts open-source models (Llama, Qwen, etc.).
- Complex tasks (e.g. agents, coding): The top choices are Claude and GPT. Claude has the best reputation for agents, tool calling, and coding (Claude Code is built on it); both vendors’ flagship prices are in the range of about $5 input / $25–$30 output per million tokens.
- Want a unified interface: Use OpenRouter. A single API key (an OpenAI-compatible interface) lets you call 300+ models from various vendors, passed through at the original price with no markup on the unit price (it only charges a one-time platform fee when you top up), making it convenient for comparing prices, switching, and failover.
Embeddings
Vector retrieval (RAG, semantic search) requires embeddings, and the commonly used option is OpenAI’s embedding models:
- text-embedding-3-small: $0.02/million tokens, 1536 dimensions by default, the best value for money and generally the first choice.
- text-embedding-3-large: $0.13/million tokens, 3072 dimensions by default, higher precision, suitable for scenarios with high retrieval-quality requirements.
- Both support reducing dimensions via the
dimensionsparameter to save storage and speed up retrieval. The older ada-002 is worse than 3-small in both quality and value, so don’t use it for new projects.
Image Generation
- Nano Banana Pro (Google, based on Gemini 3 Pro, released November 2025; the original Nano Banana was Gemini 2.5 Flash Image): Strong at multi-character/object consistency, studio-grade lighting and composition, and clear in-image text rendering; it can upscale to 4K, at about $0.13/image (1K/2K) and about $0.24/image for 4K.
- GPT Image 2 (OpenAI, model
gpt-image-2, released April 2026): An “agentic” model that brings reasoning into image generation—it plans the scene before generating and can even go online for fact-checking. It’s strong at multilingual text rendering and complex layouts (infographics, multi-panel comics), with native support up to 2K. Billed by token, which works out to about $0.006 per image (low quality) to $0.21 (high quality). There’s also a cheaper GPT Image 1 Mini option.
Video Generation
- Veo 3.1 (Google, currently the latest; there’s no Veo 4): High-quality text-to-video / image-to-video, with natively synced audio generation, supporting 1080p/4K. The per-second pricing spans a wide range, from the most economical Veo 3.1 Lite at about $0.05/second to the Standard/Quality tier (4K + audio can reach $0.6/second).
- Seedance 2.0 (ByteDance, released February 2026, API opened in April): A unified multimodal architecture with native audio-visual sync and support for multi-shot storytelling; a single request can mix multiple input images/videos/audio, and it ranks near the top in text-to-video / image-to-video evaluations. About $0.2–0.3/second (720p), with a cheaper fast tier.
Voice
- ElevenLabs: Industry-leading TTS and voice cloning, very natural-sounding, supporting multiple languages, dubbing, and conversational AI. The free tier offers about 10,000 credits per month (no commercial license), with paid plans starting at $5/month (Starter).
Other Simple Processing
For “ready-to-use” tasks like image recognition, background removal, and stylization, just go to Replicate and find an off-the-shelf model: a one-line API call, billed by runtime, and quick to get started (one image typically costs a fraction of a cent to a few cents). The downside is that private models have cold-start latency.
Deploying Your Own Model
If you want to deploy your own model, it mainly comes down to two inclinations:
- Stable, fast network, formal: Use AWS or Google Cloud (GCP). Both are enterprise-grade, with top-tier stability, compliance, and networking. You can call managed large models (AWS Bedrock, GCP Vertex AI, billed by token), or spin up GPU instances and run them yourself. The downside is that they’re expensive and have a high ops barrier—a single-GPU instance is roughly on the order of several to over ten dollars per hour (an A100 tier at about $3/hour, an H100 from about $10/hour).
- Want serverless usage-based billing: Go with RunPod or Replicate. The billing logic is charging by the actual GPU time each request occupies (down to the second)—billing stops once a request is done, and when there are no requests it scales to zero and costs nothing at all, which is especially suited to fluctuating-traffic or low-frequency scenarios. The trade-off is cold-start latency (the first incoming request has to load the model first).
Mobile Applications
Mobile is basically the various apps on phones, which can be roughly divided into two categories: one is the Apple ecosystem, and the other is the Google ecosystem.
Platforms and Distribution
There are just these two distribution channels, and you first need to register the corresponding developer account for each before you can publish:
- Apple: Distributed via the App Store, requiring an Apple Developer account, at $99/year, renewed annually.
- Google: Distributed via Google Play, requiring a Google Developer account, which is much cheaper—just a one-time $25 fee, valid for life.
Once your account is registered, you can publish and distribute your own apps on the corresponding platform.
Tech Stack
My advice for mobile is simple: just go with the combination of React Native + Expo, no need to agonize over the choice.
React Native is the underlying foundation; it lets you develop iOS and Android at the same time the React way—mostly writing React syntax, without having to touch native Swift or Kotlin, with a very low learning curve. Many large companies’ apps use it, with notable examples including Shopify (its mobile app has fully migrated to RN), Discord (the bulk of both iOS/Android uses RN), and Coinbase (which switched wholesale from native to RN starting in 2021).
Expo is a framework and toolchain built on top of React Native: you still write RN, but the development, build, and distribution stages are all packaged up for you. Out of the box it comes with routing and various SDKs for calling native capabilities, and you can use its cloud service (EAS) to directly build, upload, and distribute, sparing you the hassle of wrangling native projects yourself. It’s also friendly on cost: RN and Expo themselves are open-source and free, and EAS cloud builds come with a monthly free tier (15 Android / iOS builds each), which is plenty to start.
The day-to-day commands you’ll use are few; from creating a project to publishing, it’s basically just these:
# Create a project + local development (scan the QR code to preview live in Expo Go on a real device)
npx create-expo-app@latest myapp
npx expo start
# Before using EAS for the first time, log in and initialize the config (generates eas.json)
npm i -g eas-cli
eas login
eas build:configure
# Cloud build: --profile corresponds to a build profile in eas.json (development / preview / production)
eas build --platform ios --profile production
eas build --platform android --profile production
eas build --platform all --profile production # build both at once
# After building, submit straight to App Store Connect / Google Play
eas submit --platform ios --latest
eas submit --platform android --latest
# After release, if you change JS/assets, do an OTA hot update without going through store review again
eas update --branch production --message "fix: tweak some copy"
Among these, eas update is one of Expo’s nice perks: as long as the change is at the JS / asset layer (no native code touched), you can push it OTA directly to installed users, bypassing store review; only when you touch native dependencies do you need to re-run eas build for a full release.
Back End and Payment Logic
- Back-end logic: Almost identical to what’s described in Full Front-End/Back-End Applications, because you’re building the same kind of API.
- Payment logic: I recommend using RevenueCat. It handles the integration with Google Play and App Store’s payment capabilities, and using it is a bit like Stripe on the web side.
- Cost: Entirely free when monthly tracked revenue (MTR) is below $2,500, charging 1% of tracked revenue on the portion above that—very friendly for early-stage projects.
The nice thing about the mobile ecosystem is that Apple and Google’s capabilities really are powerful. They let you publish your app to hundreds of countries’ app stores worldwide simultaneously, through a single unified channel. Overall, developing within these two ecosystems is fairly comfortable.
Desktop Applications
Desktop is now basically the two ecosystems of Windows and Mac. Mac’s notarization system is somewhat stricter, while Windows is relatively more lax.
There are now many frameworks that can go cross-platform, and the two most widely used are probably Electron and Tauri:
Electron
Electron is essentially wrapping a Chrome engine inside for you. It’s very widely used—apps like VS Code and Claude’s desktop client are written in Electron.
- Pros: Very mature, with a complete ecosystem and not a lot of weird pitfalls; every platform uses the same Chromium, so rendering behavior is consistent, and it’s relatively easy to pick up for first-time development without stepping into traps.
- Cons: Because it embeds an entire Chrome engine, the packaged file is fairly large and memory usage runs on the high side.
Tauri
Tauri uses the system’s built-in WebView (WebView2 on Windows, WKWebView on Mac); you still write the UI in React, with the outer native shell written in Rust. For day-to-day development you basically only write front end—you only touch Rust when you need to build native extensions.
- Pros: It doesn’t bundle Chromium, so the installer is small and memory usage is also low.
- Cons: The WebView kernels differ across systems, so cross-platform rendering is prone to differences and requires testing separately; the ecosystem and ready-made plugins are also not as rich as Electron’s.
Both currently work across Windows and Mac. If it’s your first time developing and you want to play it safe, choose Electron; if you care about installer size and memory usage, you can give Tauri a try.