Your script has worked every time you have run it, which sounds like good news until you notice you have only ever run it in one place. That place is your dev server, the one you have been feeding since 2023, currently holding forty one resources, four of which you genuinely cannot remember installing. At least one of those four is quietly handing your script something it needs and never declares, and it is going to keep that secret right up until a stranger unzips your work into an empty server folder. A FiveM script launch is decided in the week before it, not on the day.
The code is usually fine. What goes wrong is packaging, documentation, a missing dependency line, an SQL file that explodes the second time somebody runs it, and the fact that the first bug report arrives at 2am with nowhere to land. This post is a release checklist that starts seven days out: clean install testing, the fxmanifest and folder layout, versioning and changelogs, choosing a support channel, the escrow decision, launch day sequencing, and the forty eight hours afterwards that quietly write your review score.
Test on a server that has never met your code
Spin up a fresh FXServer. Not a copy of your dev server with the resources folder emptied, because that keeps your cache, your database and your server.cfg habits. A new directory, a new artifact download, a blank database, a server.cfg with nothing in it but the framework and your resource.
Then break things on purpose:
- Boot without the dependency. Delete oxmysql, or ox_lib, or whatever you lean on, and watch what your script prints. If the error is a Lua stack trace about a nil value, your buyer is going to open a ticket. If it is a clear line saying which resource is missing, they are going to install it and say nothing.
- Boot on the recommended artifact and the latest one. Server owners split roughly between "recommended and never touch it" and "latest, always, for reasons". If your script needs something newer than recommended, say so on the product page before someone finds out the hard way.
- Run your SQL twice. People re-run install files. It should not matter.
- Rename the resource folder. If anything breaks, you have hardcoded the resource name somewhere and should be calling
GetCurrentResourceName()instead. - If you develop on Windows and your buyers host on Linux, test on Linux. Windows does not care that your manifest says
client/Main.luawhile the file on disk ismain.lua. Linux cares enormously, and this is the single most common "works for me" bug in the whole ecosystem.
An afternoon of this finds more than another week of feature work, and it finds the specific things that generate one star reviews rather than the things that generate feature requests.
Your fxmanifest.lua is the first documentation anyone reads
Half of the support tickets a new script generates are answered by a manifest that was written carefully. Here is one that is doing its job:
fx_version 'cerulean'
game 'gta5'
author 'yourname'
description 'Garage system with shared vehicle ownership'
version '1.2.0'
lua54 'yes'
shared_script '@ox_lib/init.lua'
client_scripts {
'client/main.lua',
'client/nui.lua'
}
server_scripts {
'@oxmysql/lib/MySQL.lua',
'server/main.lua'
}
ui_page 'web/index.html'
files {
'web/index.html',
'web/app.js',
'web/style.css'
}
dependencies {
'oxmysql',
'ox_lib'
}
escrow_ignore {
'config.lua',
'install.sql'
}
The version key matters more than people think, because it is what shows in the server console and what a buyer quotes at you when they report a bug. Keep it identical to the number in your changelog. The dependencies block turns "it does not work" into a startup message naming the thing they forgot. And files needs every asset your NUI page loads, because a missing entry there produces a blank white panel with no error at all, which is the worst failure mode available to you.
Folder naming is not cosmetic either. Lowercase, no spaces, and a short prefix of your own so your resource sorts next to your other work rather than getting lost between esx_ and qb-. The folder name is the resource name, so pick it once and never change it, because a rename after launch breaks every event, config reference and cfg line your buyers have written.
Then read your own config file as if you did not write it. Every option gets a comment saying what it does, what the units are, and what happens if you change it. "Config.Timer = 300" tells a buyer nothing. "Config.Timer = 300 -- seconds between saves, lower it if your server crashes often" tells them everything. The same discipline applies to the code behind it, and if you have not already done the work of getting the resource into a shape somebody can follow, the week before launch is your last comfortable chance.
The SQL file that gets run twice
Ship one SQL file, name it obviously, and make it survive a second run. CREATE TABLE IF NOT EXISTS for tables and INSERT IGNORE for seed rows costs you nothing. Column additions are trickier: MariaDB accepts ADD COLUMN IF NOT EXISTS and MySQL does not, so if you support both, ship a separate upgrade file per version rather than assuming.
And do not silently alter framework tables. If your script needs a column on players or owned_vehicles, say so loudly in the install instructions. Owners who discover it later assume the worst.
Start the changelog on day one
Not on day thirty, when you are trying to reconstruct what changed from git log messages that say "fix" and "fix2".
Semantic versioning is enough. Patch for fixes, minor for new options that break nothing, major for anything that requires the buyer to touch their config or their database. Ship a CHANGELOG.md inside the zip, dated, newest first, written for someone deciding whether they need to update tonight or on Sunday. "Fixed a crash when a player disconnects mid-save" is a useful line. "Various improvements" is a way of telling people to skip the update.
This is worth doing for a reason beyond tidiness. Buyers who take their servers seriously keep records of everything they run, and the ones who are good at managing a script library are comparing your version number against what they installed six months ago. A resource with a clear version history looks maintained. A resource whose downloads are all called "script_final_v2.zip" looks like a risk, no matter how good the code is.
Decide where support happens before you need it
Pick one channel and put it on the product page. A Discord with a real bug channel is fine. A form that emails you is fine. What is not fine is discovering your support strategy in public at midnight while five people DM you about the same missing dependency.
Whatever you pick, do three things before launch. Write a bug report template asking for the version, the framework, the artifact build, the exact console error and the steps to reproduce, because a report without those costs you four messages to get started. Say what your response window actually is, in plain words, and make it a promise you can keep on a bad week rather than a good one. And state the boundary: you support your script, not the interaction between your script and the other two hundred resources on their server. That sentence, written before launch, saves a great deal of awkwardness later.
Escrow or open source, and the price that follows
Cfx.re asset escrow encrypts your Lua before it reaches the buyer and ties the resource to their account and their server key, with the server checking in at boot to decrypt it. Files you name in escrow_ignore stay readable, which is why your config and your SQL belong there. It works, and it is a reasonable choice.
Understand the trade you are making. An escrowed script cannot be patched by the buyer, so every compatibility break with a new artifact or a framework update becomes your ticket, on your timeline. Your support load is structurally higher and it never goes down. It also changes how careful buyers evaluate you, because a resource nobody can read cannot be checked, and plenty of experienced owners now run an audit pass over anything they purchase before it touches a live server. Escrow does not make you suspicious, but it does mean your reputation carries weight that open code would have carried for you.
Price follows from that. Whatever number you pick, you are quoting support hours as much as features, and an escrowed script commits you to more of them. Decide your launch discount deliberately too, with an end date, rather than panicking into one on day three.
Launch day is a sequence, not a button
The last hour of a FiveM script launch should be dull, because everything in it was prepared days ago. Write the product page a few days early and let it sit, because copy written in the excitement of shipping is always too vague about what the thing actually does. Lead with the specific: what it does, what framework it needs, what it does not do.
Screenshots come from inside the game, showing the feature working, not a mockup. Take more than you need and use the clear ones. The video is worth the hour it costs: sixty to ninety seconds, install first and then the feature in use, no music louder than the voice, no thirty second intro animation. Buyers are watching to answer one question, which is whether this looks like it works.
Then publish quietly before you announce. Buy your own product, or have a friend buy it, and walk the whole path: purchase, download, unzip, install, boot. Roughly one launch in five has a broken delivery step that nobody found because the creator only ever tested the code. Announce after that walk, not before.
The forty eight hours that write your reviews
Reports will arrive, and they will not be sorted. Sort them yourself into three piles: my bug, their setup, and a feature request wearing a bug costume. Reproduce before you fix, because chasing a report that turns out to be a conflict with an unrelated resource burns an evening you do not have this week.
Ship a patch fast. Even a small one. A 1.0.1 within the first day says the script is alive and being watched, and that message reaches every person still deciding whether to buy. Pin a known issues post and update it as things land, so the seventh person with the same problem reads it instead of typing it.
Here is the part that surprises new creators. Early reviews track your response time far more closely than they track your code. A script with a rough edge and a creator who replied in twenty minutes gets rated well. A flawless script with a silent creator gets "no support" reviews inside a week, and those are extremely hard to undo. Being present for two days is worth more than two more weeks of polish.
The short version
The whole release checklist for a FiveM script launch fits in a paragraph, and almost none of it is code. Test on a clean server you have never touched, on Linux if your buyers host there. Declare your dependencies, comment your config, name your folder once and keep it. Start the changelog with version 1.0.0. Decide where bug reports go before one exists. Walk your own purchase path before announcing, then stay at your desk for two days and answer everything.
And go and find out which of those four mystery resources on your dev server has been holding your script's hand this whole time. It has done good work. It is not coming in the zip.