Deployment & Performance

AdminLTE is a static HTML/CSS/JS template — there’s nothing exotic about deploying it. But there are a handful of choices that meaningfully change page weight, time-to-interactive, and CDN reliability. This page documents the ones worth getting right.

What to deploy

The deployable artefact is everything under dist/ plus your own HTML / server-rendered templates:

dist/
├── css/                ← stylesheets (LTR + RTL, dev + minified)
│   ├── adminlte.css
│   ├── adminlte.min.css
│   ├── adminlte.rtl.css
│   └── adminlte.rtl.min.css
├── js/                 ← JavaScript bundle (dev + minified)
│   ├── adminlte.js
│   └── adminlte.min.js
└── assets/             ← demo images / fonts (replace with your own)

You don’t ship src/, node_modules/, or the demo HTML if you’re embedding AdminLTE into your own app.

Always use the .min variants in production

The minified builds are the same code with whitespace stripped and identifiers shortened. For adminlte.css the saving is roughly 15-20%; for adminlte.js it’s bigger (about 30% after gzip). The non-minified files are useful in development for readable source-map debugging — never serve them to users.

Asset Dev Production
Stylesheet dist/css/adminlte.css dist/css/adminlte.min.css
Script dist/js/adminlte.js dist/js/adminlte.min.js
RTL stylesheet dist/css/adminlte.rtl.css dist/css/adminlte.rtl.min.css
Compression at the edge

Make sure your web server / CDN gzips (or brotlis) responses for the relevant content types:

# nginx
gzip on;
gzip_types text/css application/javascript text/html image/svg+xml;
gzip_comp_level 6;
# Apache
AddOutputFilterByType DEFLATE text/css application/javascript text/html image/svg+xml

Cloudflare, Vercel, Netlify, and most managed hosting do this automatically. Verify with curl -I -H "Accept-Encoding: gzip" your-page-url and look for content-encoding: gzip in the response.

Cache headers

The dist artefacts have content hashes in their filenames only if you wire it up via your bundler — AdminLTE itself ships fixed filenames. Two reasonable strategies:

  1. Short cache + version query string (simple, works without a build pipeline):

    <link rel="stylesheet" href="/dist/css/adminlte.min.css?v=4.0.0" />
    <script src="/dist/js/adminlte.min.js?v=4.0.0"></script>

    Set Cache-Control: public, max-age=86400 (1 day) at the server. Bump ?v= on every release to force cache invalidation.

  2. Fingerprinted filenames (production-grade, requires a bundler):

    Let your bundler emit adminlte.[hash].min.css and reference that hash in your HTML. Set Cache-Control: public, max-age=31536000, immutable (1 year). This is what Vite/Webpack/Rollup do by default if you import AdminLTE through them.

CDN integrity hashes

If you load AdminLTE from a public CDN (jsDelivr, unpkg), include a Subresource Integrity (SRI) hash so a compromised CDN can’t serve malicious JavaScript silently:

<link
  rel="stylesheet"
  href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/adminlte.min.css"
  integrity="sha384-PASTE_THE_HASH_HERE"
  crossorigin="anonymous"
/>

You can get the hash from the jsDelivr file detail page — click any file and copy the “SRI” line. Do the same for Bootstrap, Popper, OverlayScrollbars, and Bootstrap Icons.

For private-hosted assets, generate the hash yourself:

openssl dgst -sha384 -binary dist/css/adminlte.min.css | openssl base64 -A
Loading order matters

Get the script order right or things break silently:

<head>
  <!-- 1. Bootstrap Icons (font CSS) — load first so icons render with the page -->
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/font/bootstrap-icons.min.css" />

  <!-- 2. OverlayScrollbars (optional, for the sidebar scroller) -->
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/styles/overlayscrollbars.min.css" />

  <!-- 3. AdminLTE — includes Bootstrap CSS via its imports -->
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/adminlte.min.css" />
</head>

<body>


  <!-- Scripts at the END of body -->
  <!-- 4. Popper (Bootstrap dependency for dropdowns/tooltips/popovers) -->
  <script src="https://cdn.jsdelivr.net/npm/@popperjs/[email protected]/dist/umd/popper.min.js"></script>

  <!-- 5. Bootstrap -->
  <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.min.js"></script>

  <!-- 6. OverlayScrollbars -->
  <script src="https://cdn.jsdelivr.net/npm/[email protected]/browser/overlayscrollbars.browser.es6.min.js"></script>

  <!-- 7. AdminLTE — must load AFTER Bootstrap -->
  <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/adminlte.min.js"></script>
</body>
Defer or async?

The AdminLTE bundle waits for DOMContentLoaded before wiring its data API, so defer is safe and recommended:

<script defer src="/dist/js/adminlte.min.js"></script>

Don’t use async — the script could execute before its dependencies (Bootstrap, Popper) have parsed, and listeners would attach to elements that don’t exist yet.

Critical CSS

For sub-1-second first paint, inline the styles that the above-the-fold layout uses (header + brand + first visible content) and load the rest of adminlte.min.css asynchronously:

<style>/* extracted critical CSS for /dashboard */</style>

<link
  rel="preload"
  as="style"
  href="/dist/css/adminlte.min.css"
  onload="this.onload=null;this.rel='stylesheet'"
/>
<noscript><link rel="stylesheet" href="/dist/css/adminlte.min.css" /></noscript>

Extract critical CSS with a tool like Critters or Penthouse as part of your build. For dashboards behind a login (where first-load speed matters less than for marketing pages), this is usually overkill.

Preload key assets

Push critical resources to the browser before it discovers them in the HTML:

<link rel="preload" as="style" href="/dist/css/adminlte.min.css" />
<link rel="preload" as="font" href="/fonts/source-sans-3.woff2" type="font/woff2" crossorigin />
<link rel="preconnect" href="https://cdn.jsdelivr.net" crossorigin />

Only preload what’s used on every page. Preloading per-route assets in a shared layout wastes bandwidth.

Lazy-loading sub-pages

If your dashboard has many routes and the JS is server-rendered HTML per route, prefer per-route CSS imports rather than one mega-stylesheet. AdminLTE’s core CSS is small (~44KB gzipped) but page-specific styles (charts, calendars, tables) can add up — only load them where they’re used.

For SPAs, code-split heavy integrations:

// Don't bundle the calendar app into the main chunk
const Calendar = () => import("./Calendar.vue")
Bundle size budget

The current published dist/ artefacts gzip to:

Asset Size (gzip)
adminlte.min.css ~40 KB
adminlte.rtl.min.css ~40 KB
adminlte.min.js ~5 KB

The full first-page payload (HTML + Bootstrap + AdminLTE + Bootstrap Icons + Popper + OverlayScrollbars) is around 180 KB gzipped when loaded from CDN. The CI build enforces a bundlewatch check that fails if any asset crosses its budget.

Service workers / offline support

AdminLTE is just static files — caching them in a service worker works without changes. A minimal Workbox config:

import { precacheAndRoute } from "workbox-precaching"

precacheAndRoute([
  { url: "/dist/css/adminlte.min.css", revision: "4.0.0" },
  { url: "/dist/js/adminlte.min.js", revision: "4.0.0" },
  // ...your own pages
])
Removing dev-only files before deploy

If you’re deploying the demo dist/ folder verbatim, strip these patterns from the upload:

  • *.map (source maps — leak source code to anyone who opens devtools)
  • **/html/ (the Astro intermediate build, if present)
  • **/.astro/ (Astro cache)

For rclone / rsync:

rsync -avz --delete \
  --exclude='*.map' \
  --exclude='html/' \
  --exclude='.astro/' \
  dist/ user@server:/var/www/your-app/
A note on Cloudflare cache

Cloudflare’s default Browser Cache TTL is 4 hours. If you push a new release and want users to see it immediately, purge the affected paths from the Cloudflare dashboard or API. Otherwise, users on cached pages will see your old CSS / JS for up to four hours.

Where to next
  • Customization — change colours, sidebar width, breakpoints before you deploy
  • Recommended Integrations — pick lightweight libraries for the things AdminLTE doesn’t bundle
  • Accessibility — make sure your deployed pages keep their a11y guarantees