I went back to Codex Desktop. Claude kept cutting me off mid-flow. Not because I’d hit a plan limit — because the platform decided I’d had enough. But I hadn’t. I was in the zone. I had more to give. Gimme more Claude! But until that changes, I’m setting myself up properly. ChatGPT Codex Desktop, local code, push to GitHub, deploy to Azure. Base44 got me here fast. Now I want to own what I built.
You built an app on a no-code platform. It works. It looks good. Users can log in, submit forms, view pages, and the backend handles the logic. But something’s been eating at you. Every API call routes through someone else’s servers. Every database query hits a managed layer you can’t inspect. Every deployment goes through a pipeline you don’t control. And every month, you pay for the privilege.
This guide is about getting out. Specifically, taking a Base44-built web application and migrating it to Microsoft Azure — your own hosting, your own infrastructure, your own rules.
It’s not quick. It’s not one-click. But it’s entirely doable if you understand what you’re actually moving and why — even if you’re not a coder. I’m doing this migration right now using ChatGPT Codex Desktop for the code work, GitHub Desktop for version control, and Azure as the final hosting destination. I set the goals. Codex wrote the code. More on that below.
Why migrate at all?
Middleware platforms are brilliant for building fast. They give you a database, authentication, file storage, API endpoints, and deployment pipelines out of the box. You skip months of setup and get straight to building features.
The trade-off is lock-in. Your app depends on their SDKs, their runtime, their data layer, their auth system, and their hosting infrastructure. You can’t pick up the code and run it somewhere else without reworking significant parts of it. And if the platform changes pricing, shuts down a feature, or disappears entirely — you’re stuck.
Migrating means you own the code, the data, the hosting, and the deployment pipeline. You control when updates ship. You control where data lives. You control the cost structure. The trade-off is that you also own the maintenance, the security patches, the infrastructure monitoring, and the 3am call when something breaks.
The tool that got me here — and the one I left behind
Let me be clear about something. Base44 is brilliant for ideation. You can spin up a working app in an afternoon — database, auth, API endpoints, the lot. If you want to test an idea, validate a concept, or build a prototype to show a client, it’s hard to beat. I’ve built real things on it. It works.
But if you want full control and ownership of your code, your website, its functions, its hosting, its deployment pipeline — exporting to Azure (or AWS, or Google Cloud, or wherever) is the G.O. Great out. Time to graduate.
Why I switched from Claude to Codex Desktop for this project
I’ve been a Claude user for a long time. But I kept hitting a wall. “You’ve reached your limit.” Except I hadn’t reached MY limit. Not a plan limit — my limit. My mental limit. My physical limit. I was in flow, deep in the work, and the platform decided I’d had enough. I hadn’t. I had more to give. The throttle was premature, aggressive, and deeply frustrating when you’re in the middle of a complex migration. Gimme more Claude. Don’t tell me when I’m done. I’ll tell YOU when I’m done.
So I went back to ChatGPT Codex Desktop. And honestly? I’m loving it. It’s way more generous for dev work. No phantom limits. No getting cut off mid-task. It just lets you work.
The workflow looks like this. I export the Base44 project, open it in Codex Desktop, and we start cleaning up the code together — stripping platform SDKs, replacing entity calls with my own API client, preparing everything for a clean push to GitHub from local. Codex handles the actual code. I handle the decisions. I know what file paths mean, what a hosting environment needs, what resources to provision. Codex turns that knowledge into working code. GitHub Desktop handles the version control — no command line, no memorising git commands, just a clean visual interface that shows what’s changed and lets me push when I’m happy with it.
From GitHub, it’s a straight pipeline into Azure. Static Web Apps for the frontend, Functions for the API, Cosmos DB for the data. Clean. Ownable. Mine.
This isn’t a Claude-vs-Codex review. They’re both good tools. But for a project like this — long, complex, code-heavy, needing sustained focus — Codex Desktop gave me the runway I needed without fighting the platform. Your mileage may vary. The point is, pick the tool that gets out of your way.
What Base44 is great at (and what it isn’t)
- Great at — rapid prototyping, idea validation, client demos, spinning up a working app in hours, not weeks
- Great at — managed infrastructure (you don’t think about servers, databases, or deployment pipelines)
- Great at — iterating fast with non-technical stakeholders who can see changes live
- Not great at — giving you ownership of the underlying code and infrastructure
- Not great at — letting you choose your own hosting, database, or deployment pipeline
- Not great at — transparent cost scaling when your app grows beyond the platform’s sweet spot
None of that is a criticism. Base44 is a tool. It’s the right tool for certain jobs and the wrong tool for others. I used it to build. Now I’m using Azure to own. Different phase, different tool.
Full disclosure — I didn’t write a single line of that code
Let me be really honest about something before we get into the technical bits. I’m not a developer. I don’t write code. If you handed me a blank file and said “build an API client layer,” I’d stare at you like you’d asked me to perform surgery.
What I am is a WordPress developer with 15 years of experience who understands site files, file paths, hosting environments, server configurations, resources, DNS, and how a web application fits together. I know what the pieces are. I know where they go. I know when something’s broken and roughly why. I just don’t write the code that makes them work.
That’s where Codex Desktop came in. Here’s how this migration actually happened.
I started by setting a concise goal. One sentence. “Migrate my Base44 app to Azure with no middleware.” I pasted that into Codex Desktop and we discussed a plan. Not line by line. Big picture. What files exist. What they do. What needs to change. What Azure services map to which Base44 features.
Codex understood the codebase. It read the files. It identified the dependencies. It suggested the replacements. It wrote the API client. It wrote the Azure Functions. It wrote the Cosmos DB connection strings. It wrote the GitHub Actions deployment config. I reviewed everything. I tested what I could. I made decisions when there were choices to make. But the code? That was Codex.
So when you see code blocks in this guide — and there are a few — they’re not mine. They’re what Codex generated during our sessions. I’m including them because they’re useful reference points if you’re doing the same thing. But I want to be clear. I directed the project. I understood the architecture. I made the calls. The typing was someone else’s brain.
If you’re a non-coder reading this and thinking “I could never do that” — you can. Not because you’ll learn to code. Because you won’t need to. Set a clear goal. Find an AI that stays out of your way. Discuss the plan. Review the output. Ship it. That’s the whole job.
Now, about that trade-off.
This guide assumes you’ve accepted that trade-off and you’re ready to do the work.
‘ve accepted that trade-off and you’re ready to do the work.What you’ll need before you start
- An exported copy of your Base44 project (frontend code, assets, and any backend function code)
- A Microsoft Azure account with an active subscription
- A GitHub account (or Azure DevOps) for version control and CI/CD
- Node.js 18+ and npm installed locally
- A code editor (VS Code, Cursor, or equivalent)
- Basic familiarity with the command line, git, and JSON configuration files
- A clear picture of what your app actually does — every page, every form, every API call, every integration
Phase 1 — Discovery and audit
Before you move anything, you need to understand exactly what you’re moving. Skip this step and you’ll discover dependencies at runtime — usually when something breaks in production.
Step 1 — Export and inspect the project
Export your Base44 project. You’ll typically get a frontend bundle (React/Next.js or similar), any backend function code (TypeScript/JavaScript), and configuration files. Download everything and open it in your editor.
Start a new local git repository. Commit the raw export as your first commit before making any changes. This gives you a clean baseline to compare against as you work.
Step 2 — Identify Base44-specific dependencies
Search the codebase for platform-specific imports and references. Look for
- SDK imports — anything from
@base44or similar package names - Entity API calls — patterns like
EntityName.list(),EntityName.create(),base44.entities - Authentication flows — references to
base44.auth, session tokens, or platform-managed user objects - File storage calls — references to platform upload endpoints, signed URLs, or media CDN paths
- Backend function patterns —
export async functionhandlers that expect platform-injected context - Automation or webhook references — scheduled tasks or entity triggers tied to platform infrastructure
- Generated routes — any routing that depends on the platform’s server-side route resolution
Document every dependency you find. Create a spreadsheet or markdown file listing each one, what it does, and what you’ll replace it with. This is your migration map.
Step 3 — Audit your data layer
Base44 entities are JSON-schema-defined collections stored in a managed database. You need to understand what data you have, how it’s structured, and how much of it needs to come with you.
For each entity, document
- Entity name and schema (all fields, types, and relationships)
- Approximate record count
- Whether row-level security is enabled (and what the rules are)
- Any automations triggered on create, update, or delete
- Any frontend code that reads or writes to this entity
Step 4 — Catalog external integrations
List every third-party service your app connects to. Payment providers, email services, OAuth connectors, API keys, webhooks. For each one, note what it does, how it’s authenticated, and whether the connection happens client-side or server-side.
This matters because platform-managed connectors often use the platform’s OAuth credentials and token management. After migration, you’ll need your own credentials and your own token refresh logic.
Phase 2 — Architecture mapping
Now you know what you have. Next step is deciding where each piece lands on Azure.
Base44 service to Azure service mapping
- Frontend (React/Next.js app) → Azure Static Web Apps. Serves your HTML, CSS, JavaScript, and static assets from Azure CDN. Supports custom domains, SSL, and routing rules.
- Backend functions → Azure Functions (serverless) or Azure App Service (if you need a persistent server). Azure Functions is the closer match — event-driven, scales to zero, pay-per-execution.
- Database entities → Azure Cosmos DB (NoSQL, closest match to JSON-schema entities) or Azure SQL Database (if you prefer relational). Cosmos DB is the natural fit — it stores JSON documents natively, supports flexible schemas, and scales horizontally.
- File storage → Azure Blob Storage. Handles images, documents, uploads. Generate SAS tokens for secure access instead of platform-managed signed URLs.
- Authentication → Azure AD (Microsoft Entra ID) for enterprise auth, or Auth0/Supabase Auth/Clerk for a lighter touch. You’re replacing platform-managed auth entirely.
- Secrets and environment variables → Azure App Settings (for non-sensitive config) and Azure Key Vault (for API keys, connection strings, and credentials).
- CI/CD pipeline → GitHub Actions (if your repo is on GitHub) or Azure DevOps pipelines. Both integrate natively with Azure Static Web Apps and Azure Functions.
- Custom domain and SSL → Managed by Azure Static Web Apps automatically. No need for separate SSL certificate management.
- Redirects and routing rules → Configured in the
staticwebapp.config.jsonfile for Azure Static Web Apps.
Decide what stays, what gets replaced, and what gets cut
Not every feature needs to survive the migration. Be honest about what’s actually used.
- Migrate as-is — static pages, design components, CSS, client-side routing, frontend assets, public content.
- Rebuild for Azure — API endpoints, database queries, file uploads, authentication, scheduled tasks, webhooks.
- Remove — platform-specific analytics dashboards, platform-managed admin panels, features tied to platform SDKs that aren’t worth rebuilding, experimental features nobody uses.
Phase 3 — Code migration
Step 1 — Strip platform SDK imports
Go through every file and remove imports from the Base44 SDK. This will break things immediately — that’s expected. The goal is to clear the platform dependency before rebuilding the connections.
Search for and remove
import { EntityName } from '@/api/entities';
import { base44 } from '@base44/sdk';
import { useAuth } from '@base44/auth';
Leave the import lines removed. You’ll replace them with your own API client calls in the next steps.
Step 2 — Create an API client layer
Instead of calling platform SDKs directly, create a thin API client layer that talks to your new Azure Functions backend. This keeps your frontend code clean and makes the backend swappable.
Create a file like src/lib/apiClient.ts
const API_BASE = import.meta.env.VITE_API_BASE_URL || 'https://your-app-api.azurewebsites.net/api';
export async function apiGet(path, params = {}) {
const url = new URL(`${API_BASE}/${path}`);
Object.keys(params).forEach(key => url.searchParams.append(key, params[key]));
const res = await fetch(url, { credentials: 'include' });
if (!res.ok) throw new Error(`API error: ${res.status}`);
return res.json();
}
export async function apiPost(path, body = {}) {
const res = await fetch(`${API_BASE}/${path}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
credentials: 'include',
body: JSON.stringify(body),
});
if (!res.ok) throw new Error(`API error: ${res.status}`);
return res.json();
}
Now replace every EntityName.list() call with apiGet('entity-name') and every EntityName.create(data) call with apiPost('entity-name', data).
Step 3 — Preserve routing and navigation
If your app uses client-side routing (React Router, Next.js routing, or similar), most of this should survive the migration intact. The main thing to watch is any routes that depended on server-side rendering or platform-managed route resolution.
For Azure Static Web Apps, create a staticwebapp.config.json file in your build output directory
{
"navigationFallback": {
"rewrite": "/index.html",
"exclude": ["/images/*", "/css/*", "/js/*"]
},
"routes": [
{
"route": "/admin/*",
"statusCode": 404
}
]
}
The navigation fallback ensures client-side routes work correctly. The admin route rule blocks access to admin paths unless you intentionally rebuild them.
Step 4 — Preserve design and assets
Your CSS, images, fonts, and design components should migrate cleanly — they’re just static files. Copy them into your project’s public or static directory. Verify that no asset URLs point to platform-hosted CDN paths. If they do, download the assets and reference them locally.
Check for platform-managed media URLs in your content. Any image or file stored on the platform’s CDN needs to be downloaded and re-uploaded to Azure Blob Storage, with the URLs updated in your code.
Phase 4 — Backend and API replacement
Step 1 — Set up Azure Functions
Create a new Azure Functions project locally using the Azure Functions Core Tools
func init api --typescript
cd api
func new --name list-entities --template "HTTP trigger" --language TypeScript
Each Base44 backend function becomes an Azure Function. The pattern is straightforward — an HTTP trigger that receives the request, processes it, and returns a response.
Step 2 — Replace entity CRUD operations
For each entity, create four functions — list, get, create, update, delete. Here’s an example using Cosmos DB
import { AzureFunction, Context, HttpRequest } from "@azure/functions";
import { CosmosClient } from "@azure/cosmos";
const client = new CosmosClient(process.env.COSMOS_CONNECTION_STRING);
const database = client.database("your-app");
const container = database.container("entity-name");
const listEntities: AzureFunction = async (context, req) => {
const { resources } = await container.items.query("SELECT * FROM c").fetchAll();
context.res = { status: 200, body: resources };
};
export default listEntities;
Repeat this pattern for each entity. The schema you defined in Base44 translates directly to a Cosmos DB container with JSON documents.
Step 3 — Replace file storage
For file uploads, create an Azure Function that generates a SAS (Shared Access Signature) token for Blob Storage. The frontend uses this token to upload directly to Azure Storage — no middleware required.
import { BlobServiceClient, generateBlobSASQueryParameters, BlobSASPermissions, StorageSharedKeyCredential } from "@azure/storage-blob";
const accountName = process.env.AZURE_STORAGE_ACCOUNT;
const accountKey = process.env.AZURE_STORAGE_KEY;
const credential = new StorageSharedKeyCredential(accountName, accountKey);
const blobServiceClient = new BlobServiceClient(`https://${accountName}.blob.core.windows.net`, credential);
const generateUploadToken: AzureFunction = async (context, req) => {
const containerName = req.body.container || "uploads";
const blobName = `${Date.now()}-${req.body.filename}`;
const containerClient = blobServiceClient.getContainerClient(containerName);
const sasToken = generateBlobSASQueryParameters({
containerName,
blobName,
permissions: BlobSASPermissions.parse("cw"),
startsOn: new Date(),
expiresOn: new Date(Date.now() + 3600 * 1000),
}, credential).toString();
context.res = {
status: 200,
body: {
url: `https://${accountName}.blob.core.windows.net/${containerName}/${blobName}?${sasToken}`,
blobName,
},
};
};
export default generateUploadToken;
Step 4 — Replace authentication
If your app had authentication, you need to rebuild it. The cleanest path on Azure is using Azure Static Web Apps built-in authentication, which supports Azure AD, GitHub, Twitter, and Google out of the box with zero configuration.
Enable it by adding authentication providers in the Azure portal under your Static Web App settings. The frontend gets user info via a standard API endpoint
const res = await fetch('/.auth/me');
const userData = await res.json();
// userData.clientPrincipal contains user info
For custom auth flows (like email/password), use a third-party provider like Auth0, Clerk, or Supabase Auth. Integrate it on the frontend and validate tokens in your Azure Functions.
Phase 5 — Data migration
Step 1 — Export your data
Export all entity records from Base44. If there’s a bulk export feature, use it. Otherwise, write a script that paginates through every entity using the API and saves records to JSON files.
Step 2 — Import to Cosmos DB
Use the Azure Cosmos DB data migration tool or write a simple Node.js script to bulk-insert records
import { CosmosClient } from "@azure/cosmos";
import * as fs from "fs";
const client = new CosmosClient(process.env.COSMOS_CONNECTION_STRING);
const database = await client.databases.createIfNotExists({ id: "your-app" });
const entities = ["blogpost", "contact", "emailcampaign"];
for (const entity of entities) {
const container = await database.containers.createIfNotExists({ id: entity });
const records = JSON.parse(fs.readFileSync(`./data/${entity}.json`, "utf-8"));
for (const record of records) {
await container.items.create(record);
}
console.log(`Migrated ${records.length} records to ${entity}`);
}
Step 3 — Verify data integrity
Count records in each container and compare against your export. Spot-check a few records to ensure fields transferred correctly. Pay attention to dates (timezone handling), nested objects, and any platform-generated fields (id, created_date, updated_date) that may need reformatting.
Phase 6 — Security checklist
- All API keys, connection strings, and secrets stored in Azure Key Vault or App Settings — never in code, never committed to git
- CORS configured on Azure Functions to only accept requests from your custom domain
- Cosmos DB firewall set to only accept connections from your Azure Functions subnet
- Blob Storage containers set to private (no public anonymous access unless intentionally public)
- HTTPS enforced on all endpoints — Azure Static Web Apps does this by default
- Admin routes blocked or protected with authentication and authorisation checks
- Rate limiting configured on Azure Functions if you’re exposed to public traffic
- Dependencies updated to latest stable versions (run
npm auditand fix vulnerabilities) .envfiles added to.gitignore— never commit environment configuration with real credentials
Phase 7 — CI/CD and deployment
Step 1 — Push to GitHub
Push your cleaned-up codebase to a GitHub repository. Structure it with two main directories
your-app/
├── frontend/ # The static web app (React/Next.js)
├── api/ # Azure Functions (backend)
├── .github/
│ └── workflows/
│ └── deploy.yml
└── README.md
Step 2 — Create Azure resources
In the Azure portal, create
- An Azure Static Web App (for the frontend)
- An Azure Functions App (for the backend API)
- An Azure Cosmos DB account (for the database)
- An Azure Storage account (for file uploads)
- An Azure Key Vault (for secrets)
Step 3 — Configure GitHub Actions
Link your GitHub repository to Azure Static Web Apps. Azure generates a GitHub Actions workflow automatically. For the Azure Functions backend, add a deployment step to the same or a separate workflow
name: Deploy to Azure
on:
push:
branches: [main]
jobs:
deploy-frontend:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build frontend
run: |
cd frontend
npm ci
npm run build
- name: Deploy to Static Web App
uses: Azure/static-web-apps-deploy@v1
with:
azure_static_web_apps_api_token: ${{ secrets.AZURE_SWA_TOKEN }}
repo_token: ${{ secrets.GITHUB_TOKEN }}
action: "upload"
app_location: "frontend"
output_location: "dist"
deploy-api:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Deploy Azure Functions
uses: Azure/functions-action@v1
with:
app-name: your-app-api
package: api
publish-profile: ${{ secrets.AZURE_FUNCTION_PUBLISH_PROFILE }}
Phase 8 — Testing and acceptance
Before you switch DNS, test everything on the staging URLs Azure provides.
Functional testing checklist
- Every page loads without errors (check browser console)
- Every form submits and saves data correctly
- Every API endpoint returns expected responses
- File uploads work and files are accessible via Blob Storage URLs
- Authentication login and logout work
- Protected routes redirect unauthenticated users
- Search and filtering work if your app has them
- Responsive layout works on mobile, tablet, and desktop
- All assets load (images, fonts, CSS) — no broken links
Performance testing
- Run Lighthouse audit on key pages — aim for 90+ on performance, accessibility, best practices, and SEO
- Check API response times — should be under 500ms for most operations
- Verify CDN caching is working for static assets
- Load test API endpoints if you expect high traffic
Content and metadata verification
- All page titles and meta descriptions are present and correct
- Open Graph tags work (test with social media preview tools)
- JSON-LD structured data is present if applicable
- Canonical URLs point to the correct domain
- Robots.txt and sitemap.xml are accessible
- 301 redirects from old URLs are configured in
staticwebapp.config.json
Phase 9 — DNS cutover
Step 1 — Configure custom domain in Azure
In the Azure portal, go to your Static Web App and add your custom domain. Azure will provide a CNAME record to add to your DNS configuration. SSL certificates are provisioned automatically — no manual setup needed.
Step 2 — Update DNS records
At your DNS provider, add the CNAME record pointing your domain to the Azure Static Web App URL. Keep your old DNS records active until propagation completes.
Step 3 — Verify and monitor
After DNS propagation (usually 15 minutes to a few hours), verify the domain loads correctly. Check that HTTPS works, that SSL is valid, and that all pages are accessible on the new domain. Monitor Azure Application Insights for errors over the first 48 hours.
Phase 10 — Rollback plan
If something goes wrong after cutover, you need a way back. Before you switch DNS
- Keep the original Base44 app running and accessible for at least 30 days after migration
- Document the exact DNS records you changed and their previous values
- Keep a backup of your exported data and code
- Set up Azure Application Insights alerts for error rate spikes — if errors exceed 5% of requests, trigger rollback
- Rollback procedure — revert DNS records to original values, confirm the old app is serving traffic, investigate and fix issues on the Azure deployment, retry cutover when ready
After migration — what you now own
This is the part most migration guides skip. Once you’re live on Azure, you own the full stack. That means
- Updates — npm dependencies, Azure Functions runtime, Node.js version, framework patches. Schedule monthly maintenance windows.
- Security — rotate keys and connection strings quarterly. Monitor Azure Security Centre for vulnerabilities. Apply security patches within 48 hours of release.
- Monitoring — set up Application Insights alerts for error rates, response times, and availability. Configure uptime checks. Review weekly.
- Costs — Azure bills per execution for Functions, per RU for Cosmos DB, per GB for Storage. Monitor usage monthly. Set up budget alerts in Azure Cost Management.
- Backups — Cosmos DB automatic backups are enabled by default, but verify retention settings. For Blob Storage, enable versioning. Test restore procedures quarterly.
- Hosting environment understanding — know your Azure resource group structure, understand your networking configuration, and document how your resources connect to each other. If you hand this project to another developer, they should be able to understand the architecture from your documentation alone.
Owning your infrastructure is freedom. It’s also responsibility. The middleware platform absorbed all of this — updates, security, monitoring, backups, scaling. Now it’s yours. Budget time for it. Don’t treat maintenance as an afterthought.
The honest summary
Migrating off a middleware platform is not a one-click operation. It’s a multi-week project that requires you to understand your app at a level the platform was designed to hide from you. You’ll need to rebuild your backend, replace your auth system, migrate your data, and configure your own infrastructure.
But what you get at the end is something you fully control. Your code, your data, your hosting, your deployment pipeline. No platform lock-in. No surprise pricing changes. No risk of the platform shutting down a feature you depend on.
The trade-off is maintenance. You own it now — security patches, infrastructure updates, monitoring, backups. That’s the cost of freedom. It’s not free, but it’s yours.
And to be fair to Base44 — without it, I wouldn’t have had an app to migrate in the first place. It got me from idea to working product faster than anything else could have. That’s not nothing. That’s actually everything. But there comes a point where you’ve outgrown the training wheels. You want to feel the road. For me, that meant Codex Desktop for the code work, GitHub Desktop for version control, and Azure for hosting. I didn’t write the code. I directed the project, made the decisions, and Codex executed. Your stack might look different. The principle is the same. You don’t need to be a coder. You need to be a director.
Want this kind of setup? Let’s talk →
Frequently asked questions
Can I migrate only part of my app and keep the rest on the platform?
Technically yes, but it creates a hybrid dependency where part of your app still relies on platform infrastructure. This defeats much of the purpose. If you’re going to migrate, commit to the full move. The complexity of maintaining two systems in parallel usually exceeds the effort of finishing the migration.
How long does a typical migration take?
For a medium-complexity app (5-10 entities, standard CRUD operations, a few integrations), expect 2-4 weeks of focused work. Larger apps with complex auth flows, dozens of entities, and heavy integrations can take 6-8 weeks or more. The discovery phase usually takes longer than people expect — budget at least a full week just for auditing.
What happens to my data if something goes wrong during migration?
Your original data stays on the platform until you explicitly remove it. The migration process copies data — it doesn’t move it. Keep the original Base44 app running for at least 30 days after cutover as a fallback. If you need to roll back, your data and your app are still there.
Is Azure the only option for self-hosting?
No. AWS, Google Cloud, DigitalOcean, or any VPS provider will work. The principles are the same — you need static hosting for the frontend, serverless functions or a server for the API, a database, and file storage. This guide uses Azure because it provides the most integrated tooling for this type of migration, but the architecture maps to any cloud provider.
What is an SDK and why do I need to strip it?
SDK stands for Software Development Kit. Think of it like a cake mix. Instead of baking from scratch, you use the pre-packaged mix that comes with everything measured out. It is convenient, but it only works with that brand’s recipe. Base44 gives you their own SDK with pre-written code shortcuts that make building easy. But when you move to Azure, those shortcuts do not work anymore. You need to swap the cake mix for from-scratch recipes. That is what “stripping SDK imports” means. Removing the platform’s pre-written shortcuts and replacing them with code that works on your own hosting. If you are using an AI coding tool like Codex, it handles this for you. You just need to know it exists.
This guide contains no affiliate links. It is a technical how-to resource based on real migration experience. All hosting, maintenance, and infrastructure decisions are your responsibility. Always test migrations in a staging environment before DNS cutover. Back up your data before making any changes. The author and LoudCow accept no liability for data loss, downtime, or infrastructure issues arising from following this guide.


