Resource packs are one of the most powerful and most misunderstood tools on a Minecraft server. They can repaint every block, swap a sword model, rewrite the sounds a player hears, and change the font in the chat box, all without touching the game logic. Yet the moment you need to host a pack on a server, force it on players, or push it to Bedrock clients through Geyser, the details get fiddly fast and support channels fill up with “why do I see purple and black blocks” threads.
This guide exists for one reason: to help. It is a complete, practical walkthrough of hosting, distributing, and forcing resource packs, written so that a server owner, administrator, or staff member can set things up correctly on the first try. We wrote it after running packs across a mix of Paper and vanilla servers, timing how long clients wait on a content delivery network versus a self-hosted file, and watching how Java and Bedrock players respond to optional and required packs. Everything here is grounded in the official pack format, the vanilla server.properties options, and the GeyserMC documentation, so you can copy a working configuration instead of reverse-engineering one.
It is written for the people who keep a community running, and for plugin coders who ship packs alongside their plugins. By the end you will know what a resource pack really is, how to host and distribute one, how forcing behaves, how packs merge and conflict, and how to reach Bedrock players too. If you are still choosing your server software, our [A Beginner’s Guide to Minecraft Server JARs: Paper, Purpur…] is a good place to start before you worry about packs at all.
What Resource Packs Actually Are
A resource pack is a folder (usually shipped as a ZIP) that replaces the client-side assets of Minecraft: textures, block and item models, sounds, particle definitions, fonts, and language files. The client downloads it, reads a manifest, and swaps the assets it points to. Crucially, a resource pack only changes how the game looks and sounds. It does not add blocks, change recipes, or run any server logic. That work belongs to a different system entirely.
Resource pack vs data pack vs plugin
Confusing these three is the single most common mistake we see. A player downloads a “cool new mob” pack, drops it into the server, and wonders why nothing happens. The table below is the source of truth for what each type does, where it lives, and who loads it.
| Type | Where it lives | Changes visuals | Loaded by | Typical use |
|---|---|---|---|---|
| Resource pack | Server or client (resourcepacks folder) | Yes | The client | Textures, models, sounds, fonts, language |
| Data pack | world/datapacks | No | The server (per world) | Recipes, loot tables, advancements, functions, structures |
| Plugin | plugins/ on the server software | No (unless it ships a pack) | The server | Gameplay logic, commands, economy, APIs |
| Mod | mods/ (both sides for most) | Sometimes | Client and/or server | Deep game changes, new content, loaders |
pack.mcmeta and pack_format explained
Every valid resource pack contains a pack.mcmeta file at its root. This small JSON file tells the client which pack format the assets target, and optionally what to display in the in-game pack list. The format number matters: it changes every time Mojang alters the asset structure, and a mismatch is exactly what produces the dreaded “incompatible pack” warning.
{
"pack": {
"pack_format": 34,
"description": "My Server Resource Pack"
}
}The exact number depends on your Minecraft version. Each major release tends to bump the value, and the authoritative list lives on the Minecraft Wiki pack format page. Check it every time you update the server. If your pack was built for an older format, the modern client will often still load it but flag it as outdated, and some newer asset types may simply not render.
Hosting a Resource Pack: Where the Files Live
Server-side vs client-side packs
There are two ways a pack can reach a player. In a client-side setup, players download the pack themselves and place it in their resourcepacks folder, enabled through Options, Resource Packs. In a server-side setup, the server hosts the pack at a URL and the client downloads it automatically when it connects. Server-side distribution is what makes a consistent community look possible, because you do not have to convince every player to install anything.
URL requirements: direct link, HTTPS, and CORS
The URL you put in server.properties must meet three conditions that trip up most first attempts.
- Direct file link. The URL must serve the ZIP bytes directly. A link to a download page, a Google Drive “view” link, or a Discord attachment page will fail, because the client receives HTML instead of a ZIP.
- HTTPS. Modern Minecraft clients expect an encrypted connection. Plain HTTP links are frequently rejected outright, so always host behind TLS.
- Reachable and CORS-friendly. The client fetches the file directly, so it must be publicly reachable, must not require cookies or a login, and should not be blocked by restrictive cross-origin rules or hotlink protection.
When a link violates any of these, the client quietly falls back to default textures and, if the pack was required, may drop the connection. Always open the URL in an incognito browser window and confirm it starts downloading a file named yourpack.zip.
Content delivery options
Where you host the ZIP decides how fast players get in and how much bandwidth you burn. Here is how the common options compare.
| Option | Good for | Trade-off |
|---|---|---|
| Object storage + CDN (S3, Backblaze B2, Cloudflare R2 + CDN) | Public servers with many players | Slight setup effort; small cost at scale |
| Self-hosted web server on the game box | Small private servers | Competes with the game for bandwidth and CPU |
| A GitHub release asset | Small to medium packs, versioned | Not a true CDN; can be slow or rate-limited |
| Free file hosts with interstitial pages | Nothing serious | Interstitial pages break direct download |
For any public server, an object store fronted by a CDN is the right answer. The pack is cached at the edge, players download from a nearby node, and your game server never spends a byte of its own bandwidth shipping textures. If you run your server on a managed host, check whether they already offer a static file endpoint before paying for anything.
If you are still narrowing down which server software you run, note that the choice barely affects resource pack delivery. Both work identically with the same server.properties keys, as covered in our [How to Migrate from Spigot to Paper Without Breaking Plugins] guide.
Wiring Packs Into server.properties
The vanilla server exposes resource pack controls directly in server.properties. The block below is a realistic configuration for a server that distributes a pack and asks players to accept it.
resource-pack=https://cdn.example.com/packs/mytextures-v3.zip
resource-pack-sha1=2c26b46b68ffc68ff99b453c1d30413413422d70
resource-pack-prompt={"text":"Please accept our server pack for the full experience.","color":"gold"}
require-resource-pack=true
require-resource-pack-prompt={"text":"This server requires the pack to play.","color":"red"}resource-pack and resource-pack-sha1
resource-pack is the direct HTTPS URL to your ZIP. resource-pack-sha1 is the SHA-1 hash of that exact file. The hash is optional, but you should always set it: the client uses it to verify the download completed intact and to skip re-downloading a pack it already cached. If you replace the ZIP without updating the hash, clients may keep using the old cached copy. Generate the hash with a one-liner such as sha1sum mytextures-v3.zip (or certutil -hashfile mytextures-v3.zip SHA1 on Windows) and paste the lowercase hex value.
resource-pack-prompt
resource-pack-prompt is a JSON text component shown on the confirmation screen. It is your one chance to explain, in the client dialog, why the pack is worth accepting. Keep it short, honest, and styled. A gold or yellow message reads as a friendly request; a wall of text reads as spam and gets declined.
require-resource-pack and require-resource-pack-prompt
require-resource-pack flips the pack from optional to mandatory. When set to true, a player who declines or fails the download is disconnected. require-resource-pack-prompt overrides the message shown when the player is about to be kicked, letting you explain the reason instead of showing a generic disconnect. Note that require-resource-pack-prompt is ignored unless require-resource-pack is true.
How clients are prompted
When a Java client connects, it receives the pack URL and prompt, then shows a confirmation dialog before joining. Three things can happen: the player accepts and the pack downloads and applies; the player declines and, if the pack is optional, joins with default textures; or the download fails and the player is either dropped (required) or let in (optional). A slow CDN means a long loading screen, and a broken URL means players sit at “Downloading terrain” until it times out, so monitor your pack URL like you monitor the server itself.
Forcing vs Optional Packs: UX and Fairness
Forcing a pack, by enabling require-resource-pack, guarantees every player sees the same world. That consistency is essential for servers that use custom models to convey information: a colored “hospital” block, a hidden-door texture, a resource that only renders correctly with your pack. Without it, players on default textures see a plain, misleading world. But forcing has real costs. A mandatory pack is a hard gate: anyone whose connection drops mid-download, whose antivirus blocks the CDN, or who simply refuses is kept out. For a large public server this can turn a curious newcomer into a bounce. Force only when the pack is genuinely required for fair play, and keep the ZIP small so downloads are quick.
When forcing is fair
- The pack encodes gameplay-relevant information, such as team colors, hidden entrances, or custom GUI elements.
- The pack is small (a few megabytes) and served from a fast CDN, so acceptance is a formality.
- You clearly state the requirement before players join, so no one is surprised by a disconnect.
- You keep the pack up to date so cached copies do not drift from the server version.
When the pack is purely cosmetic and the default textures look fine without it, when the ZIP is large, or when your audience includes many Bedrock players, an optional pack is the wiser choice. Optional packs maximize join rate and let enthusiasts opt in.
Merging Behaviour, Priority, and Conflicts
Minecraft can load many packs at once, and it merges them with a clear priority order. When two packs define the same asset, the higher-priority pack wins for that asset, but the lower one still supplies everything it uniquely provides. The server pack is delivered as a “server pack” and sits above the client default, which is why players cannot simply toggle it away and expect your custom textures to still appear.
- The server-sent pack is applied on top of whatever the player has selected, for the assets it defines.
- Player-selected packs that are placed above the server pack in their own list can override the same assets.
- Assets the server pack does not touch are unaffected, so player packs remain visible for everything else.
- Format mismatches can cause the client to fall back to defaults instead of merging, producing missing textures.
Why client packs conflict with server packs
Any pack a player enables competes for the same texture keys. If a player runs a high-resolution PvP pack that retextures swords, and your server pack also retextures swords, the client decides the winner by list order. The result is inconsistent: items that render correctly for one player look wrong for another. On a competitive server, that inconsistency can be exploited. The fix is not to fight the client, but to deliberately scope your server pack to only the assets that matter for fair play, so overlap and confusion stay minimal.
Bedrock and Geyser: Crossplay Delivery
If your network includes Bedrock players, resource packs work differently. Geyser translates between the Java server and Bedrock clients, and it includes its own resource pack handling. The cleanest approach is to build a separate Bedrock-format pack, because Bedrock does not understand Java resource packs, then let Geyser deliver it.
- Bedrock packs use a different manifest structure: a manifest.json with a UUID-based header and module list, not pack.mcmeta.
- Geyser can be pointed at a Bedrock pack so it is pushed to connecting Bedrock players automatically.
- A conversion tool or a hand-built companion pack is needed if you want the same look on both platforms.
- Keep the Java and Bedrock packs in sync by version, or crossplay players will see two different servers.
Read the GeyserMC documentation for the exact resource pack configuration keys, and see our overview at [A Guide to GeyserMC: Bridging the Gap Between Java and Bedrock] for how the bridge works end to end. If you are building a plugin list for a crossplay server, [Top Java Plugins That Work on Bedrock via GeyserMC] covers which Java plugins pair cleanly with Geyser. One caveat: forcing is a Java-side concept. There is no require-resource-pack equivalent that hard-kicks a Bedrock player, so on a crossplay server your “forcing” is really a Java-only guarantee. Plan your UX around that reality.
Optimizing Packs: Compression, Resolution, Bandwidth
Pack size is the difference between a two-second loading screen and a two-minute one. The good news is that most packs are far larger than they need to be.
- Compress textures well. PNG optimization tools and modern formats cut size dramatically with no visible change at typical viewing distances.
- Prefer 16x or 32x base resolutions for network use. 64x and 128x packs can be tens or hundreds of megabytes.
- Reuse a small palette and atlas where possible instead of shipping hundreds of near-identical images.
- Serve from a CDN and set long cache lifetimes. Add the SHA-1 hash so clients revalidate correctly after an update.
- Version your pack filename (mytextures-v3.zip) so a new URL forces a fresh download instead of a stale cache hit.
When to split packs
A single monolithic pack is easy to distribute but hard to maintain and slow to download. Splitting helps when different parts of your server need different assets. Server packs can be layered, so you can ship a small always-on core pack for fair-play assets and larger optional cosmetic packs per game mode. The core pack stays tiny and can be forced safely, while the heavy content is opt-in. Track the total download as players experience it: if the forced pack plus any plugin-sent packs together exceed a few megabytes, audit what is actually necessary and move the rest behind optional downloads.
Pros and Cons of Server-Forced Resource Packs
Pros
- Every player sees a consistent, intended world with no per-player setup.
- Gameplay-critical information, such as custom GUI and marker blocks, renders correctly for everyone.
- Central updates: change the pack once and all clients pick up the new version.
- A polished look raises the perceived quality of the whole server.
Cons
- A download failure or refusal can block a player from joining at all.
- Large forced packs slow down every connection and hurt first impressions.
- You take on CDN bandwidth costs and the responsibility of keeping the URL alive.
- Bedrock players cannot be force-gated the same way, so crossplay consistency is only partial.
Common Mistakes and Expert Tips
- Linking to a download page instead of the file. The client needs the raw ZIP. Test in incognito and confirm a download begins.
- Forgetting the SHA-1 hash. Without it, clients may reuse a stale cached pack and players report “it did not update”.
- Burying pack.mcmeta in a subfolder. The manifest and assets must be at the ZIP root, not inside an extra directory.
- Using plain HTTP. Modern clients reject or warn on unencrypted pack URLs. Always use HTTPS.
- Forcing a huge pack. Force the small core, make the big cosmetics optional.
- Ignoring Bedrock. Crossplay players need a separate Bedrock-format pack; Java packs will not load there.
- Never testing a declined prompt. Connect with the pack check unchecked and confirm the optional path still lets you in.
Expert tip: keep a staging pack URL for testing and a production URL for players, so a broken edit never reaches your community. Pair every pack change with a format-number check against the pack format page for your exact server version.
Frequently Asked Questions
A resource pack changes how the game looks and sounds (textures, models, sounds, fonts) and is loaded by the client. A data pack changes game data such as recipes, loot tables, advancements, and functions, and is loaded by the server per world. If you want existing blocks to look different, use a resource pack; if you want new recipes or behavior, use a data pack.
Host the pack as a direct HTTPS ZIP, set resource-pack to its URL and resource-pack-sha1 to the file hash, then set require-resource-pack=true so players who decline are disconnected. Add require-resource-pack-prompt to explain why. This applies to Java clients; Bedrock players through Geyser are handled differently.
No. Bedrock uses a different pack format, built around a manifest.json with UUIDs rather than pack.mcmeta. To give Bedrock players custom textures you must build a Bedrock-format pack and let Geyser distribute it, ideally keeping it in sync with your Java pack by version.
It depends on priority. The server-sent pack is applied on top for the assets it defines, but a player can place their own selected packs above it in their list to override the same assets. Assets your server pack does not touch are unaffected. That is why well-built server packs scope themselves to only the textures that matter.
Conclusion: Ship Packs Players Actually Accept
Resource packs are the fastest way to make a server feel bespoke, but a pack is only as good as its delivery. Get the format right, host the ZIP on a fast HTTPS CDN with a valid hash, choose forcing or optional based on fairness rather than convenience, and remember that Bedrock needs its own pack through Geyser. Do those things and the purple-and-black blocks, the failed downloads, and the “why does it look different for me” tickets simply stop happening.
Your next step is concrete: open your server.properties, add the resource-pack and resource-pack-sha1 lines from this guide, upload the pack to an object store, and test with a fresh client and a declined prompt. Then review your crossplay path with [A Guide to GeyserMC: Bridging the Gap Between Java and Bedrock] and keep your server software current using [How to Migrate from Spigot to Paper Without Breaking Plugins]. A few careful minutes now saves hours of support later.

Leave a Reply