WordPress without plugins brings surprisingly high performance when I set up caching, images, code, server setup and theme specifically. With a wp minimal setup I have achieved 30-60 percent faster loading times in projects - without any additional extensions.
Key points
- Caching via .htaccess significantly accelerates repeat calls.
- pictures compress before uploading and use WebP.
- Code keep it lean, remove unnecessary CSS/JS.
- Fonts local or system fonts.
- Server-settings and configure PHP sensibly.
Activate browser caching: faster loading without additional tools
My first bet is on Browser caching, because recurring visits benefit massively. I store Cache-Control and Expires headers in the .htaccess so that the browser stores static files for longer and Inquiries is reduced. A few lines such as ExpiresActive On and suitable max-age values are sufficient for this, which takes less than a minute. In tests, the loading time is noticeably reduced, often by 30 to 40 percent for subsequent calls. If you want to go deeper, read my approach in Pagespeed without plugins and adjusts the times for each file type.
Example header in the .htaccess
I set long expiration times for static assets and mark unchanged files as immutable, so that the browser does not validate unnecessarily:
# Activate caching
ExpiresActive On
ExpiresDefault "access plus 1 month"
ExpiresByType image/webp "access plus 1 year"
ExpiresByType image/avif "access plus 1 year"
ExpiresByType image/jpeg "access plus 1 year"
ExpiresByType image/png "access plus 1 year"
ExpiresByType image/svg+xml "access plus 1 year"
ExpiresByType text/css "access plus 1 year"
ExpiresByType application/javascript "access plus 1 year"
ExpiresByType font/woff2 "access plus 1 year"
# Cache control with immutable for versioned files
Header set Cache-Control "public, max-age=31536000, immutable"
# Keep HTML deliberately short (no long-term caches)
Header set Cache-Control "no-cache, no-store, must-revalidate"
WordPress usually provides assets with version parameters (e.g. ?ver=1.2.3). This form of versioning harmonizes with long cache times and immutable, because a new URL is automatically created when changes are made.
Validation and consistency
I usually leave Last-Modified active and do not use ETags when working behind load balancers to avoid unnecessary revalidations. It remains important: Do not cache HTML aggressively to keep content and session states up to date.
Optimize images: WebP, size and lazy loading
Images often determine the amount of data of a page, so I always compress them before uploading. For photos I choose JPG or WebP, for graphics WebP or PNG, depending on the motif and the size. Quality. Hero graphics I keep under 200 KB and prepare several sizes for different widths. This way, WordPress delivers the right variant depending on the viewport and saves on transfer. I also use lazy loading by using the loading=“lazy“ attribute or the standard WordPress function.
Responsive images and sizes
I pay attention to correct width- and height-attributes to avoid layout jumps (CLS). With srcset I define suitable sizes, so that the browser does not load too large variants. For the hero image, I set the attribute fetchpriority="high", so that the LCP element is prioritized early on. Where it makes sense, I use AVIF as an alternative to WebP, but keep an eye on the fallbacks.
Clean placeholders instead of FOUC
I work with CSS-aspect-ratio or conservative placeholders so that the space is reserved for images. This keeps the interaction calm and the Core Web Vitals stable.
Code optimization without additional tools
I clean up first CSS and remove rules that don't apply anywhere. I then summarize JavaScript, dispense with jQuery for small things and load scripts with defer. Where appropriate, I minimize HTML, CSS and JS with simple online tools so that spaces and comments disappear. This often significantly reduces file sizes and speeds up transmission. I also check whether I include critical CSS directly in the head and load the remaining styles with a delay.
Critical CSS and render priorities
The above the fold-layout with small inline CSS, while the rest is done via media=“print“-Hack or rel=“preload“ plus onload-switch is loaded later. Moderation is important: An inline block that is too large slows down HTML transfer and TTFB.
JavaScript: Defer, Async and modules
I set scripts to defer, if they are DOM-dependent, and on async with independent trackers. Modern bundles can be used as type=“module“ which has automatic defer semantics. I consistently avoid blocking inline JS in the head.
Reduce external resources: fewer requests, more control
Every external request costs time and control, so I rely on System fonts or locally hosted fonts. Instead of obtaining Google fonts via a CDN, I load the files into my own installation and deactivate unnecessary font styles. For analytics and embeds, I also make a conscious decision as to whether I need scripts or whether a more streamlined Solution is sufficient. To evaluate the effect without page cache, I use a Live check without page cache and measure the pure server and frontend performance. In this way, I keep external dependencies to a minimum and accelerate the time to first byte.
Targeted use of resource hints
If I do need external domains, I set preconnect/dns-prefetch sparingly and only for really critical hosts. For locally hosted fonts preload to the WOFF2 file of the primary font including font-display: swap, so that text is immediately visible.
Setting the PHP and server configuration sensibly
I set a current PHP-version and activate OPcache, because dynamic responses benefit greatly from this. For lean websites, 128 MB memory limit is often sufficient, while heavily expanded installations require more; too high a limit wastes resources, too low a limit produces a lot of data. Error. In addition, I optimize max_execution_time and max_input_vars to the actual requirements. On the server side, I activate GZIP or Brotli, keep keep-alive active and use HTTP/2 or HTTP/3, if available. These measures shorten server time and speed up the construction of the page even before rendering.
Relieve WP-Cron
Many installations call up tasks too frequently, which Response time noticeably influenced. I therefore check how often cron jobs are running and move infrequent jobs to real system cron entries. If you are unsure here, you can find a compact explanation at Optimize WP-Cron and then sets intervals more sensibly. In this way, I reduce unnecessary PHP calls and stabilize the Performance at peak load. The result is more consistent response times and less idle load.
OPcache with a sense of proportion
I give OPcache enough memory and deactivate expensive checks in production. Example values that have proven themselves:
; php.ini / opcache.ini
opcache.enable=1
opcache.enable_cli=0
opcache.memory_consumption=192
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=20000
opcache.validate_timestamps=0 ; in production via deploy clear
opcache.revalidate_freq=0
In development environments I activate validate_timestamps again so that changes are immediately visible.
PHP-FPM and module brakes
I adapt the PHP-FPM process manager to the traffic profile (e.g. pm = dynamic, sensible pm.max_children) and remove developer modules such as Xdebug in production. I log error messages, but do not output them (display_errors=0) to reduce response size and risk.
Lightweight theme instead of feature ballast
A lean theme sets the Base for fast pages, which is why I avoid feature giants with thick sliders and countless shortcodes. Modern block themes or minimalist classics such as GeneratePress or Blocksy bring little overhead and focus on clean and simple design. Code. I build small interactions with vanilla JS, styles in modular CSS files. I deactivate functions that I don't use and remove superfluous templates. This way I keep the render chain short and avoid unnecessary requests.
Remove WordPress ballast in the theme
A few lines in the functions.php remove overhead without using plugins:
// Disable emojis
remove_action('wp_head', 'print_emoji_detection_script', 7);
remove_action('wp_print_styles', 'print_emoji_styles');
// deactivate oEmbed service and scripts if not needed
remove_action('wp_head', 'wp_oembed_add_discovery_links');
remove_action('wp_head', 'rest_output_link_wp_head');
add_action('wp_footer', function(){ wp_dequeue_script('wp-embed'); });
// Load dashicons only in the backend
add_action('wp_enqueue_scripts', function(){
if (!is_user_logged_in()) { wp_deregister_style('dashicons'); }
});
// remove jQuery Migrate in the frontend (only if compatible)
add_action('wp_default_scripts', function($scripts){
if (!is_admin() && !empty($scripts->registered['jquery'])) {
$scripts->registered['jquery']->deps =
array_diff($scripts->registered['jquery']->deps, ['jquery-migrate']);
}
});
I test thoroughly after every change to avoid incompatibilities. Especially when removing jQuery Migrate, a functional test is mandatory.
Tidy up the database: less ballast, faster queries
I delete old Revisions, drafts and recycle bin content and limit new versions in wp-config.php. I also shorten overdue transients and check autoload options that would otherwise be unnecessarily stored on page startup. I keep comment moderation and spam removal clean so that tables remain compact and Indices work efficiently. If you know your way around, optimize the tables once a month. Every reduction in the amount of data speeds up queries and backend calls noticeably.
Keep an eye on autoload options
Too large autoload-entries slow down every request. Ideally, I keep the total under a few MB. Example check (adjust table prefix):
SELECT SUM(LENGTH(option_value)) AS autoload_bytes, COUNT(*) AS rows
FROM wp_options WHERE autoload='yes'; I specifically reduce values that are out of the ordinary and set rarely used options to autoload = no.
Limit transients and revisions
I clean up expired transients cyclically, for example with a simple SQL delete to _transient_timeout_%-entries. In the wp-config.php I set reasonable limits:
define('WP_POST_REVISIONS', 5);
define('EMPTY_TRASH_DAYS', 7); In this way, the database remains manageable without completely dispensing with the history.
Realistic expectations and limits
A minimal approach is ideal for blogs, company websites and projects with manageable Content. As soon as many simultaneous users, store functions or complex personalization come into play, I reach my limits without a full-page cache Limits. For WooCommerce and news portals, I will consider targeted caching solutions later. The decisive factor remains: First set a clean base, then expand if necessary. This way, I avoid plugin proliferation and retain full control over loading times.
WooCommerce special features
On store pages, I avoid resource-intensive scripts outside of the shopping cart/checkout context. wc-cart-fragments I deactivate it on pages that do not require a dynamic shopping cart display and load it specifically where it is needed. This noticeably reduces the JS load.
Practical implementation and successful results
I work step by step, measuring after each Amendment and document times and effects. Typical process: caching headers, image compression with WebP, code shortening, reduction of external resources, theme decision, server tuning and database maintenance. In one example, loading times fell from 1.3 seconds to 0.78 seconds, which corresponds to a good 40 percent. The increase is reflected in better Core Web Vitals and noticeably smoother loading times Interaction. The following table classifies the costs and benefits.
| Measure | Time required | Typical profit |
|---|---|---|
| .htaccess caching header | 10-15 minutes | large for repeat calls |
| Images on WebP + sizes | 30-60 minutes | Very large with image load |
| Clean up CSS/JS + minify | 60-120 minutes | Medium to large |
| Reduce external resources | 30-60 minutes | medium |
| Keep theme lean | 30-90 minutes | medium |
| Fine tune PHP/Server | 30-60 minutes | medium |
| Database maintenance | 20-40 minutes | medium |
I test each level separately and check TTFB, Largest Contentful Paint and Interactivity. This allows me to reliably identify which measures are really working. I only add special technology such as edge caching or image CDNs once the basis is in place. This prevents bad investments and keeps the Complexity small. The result remains measurable and consistent.
Frequent brakes and quick fixes
- Missing widths/heights for images: leads to CLS - always specify or work with aspect-ratio.
- Too many font stylesRegular/Bold/Italic are often sufficient; prioritize WOFF2, preload local fonts.
- Unnecessary jQuery dependenciesWrite small interactions in Vanilla JS, replace plugins.
- Synchronous third-party scriptsSet async/defer or delete completely if not business-critical.
- Large inline scripts in the head: store in files, prioritize correctly.
- Oversized picturescorrect breakpoints and sizes, downsizing on the server side.
- Autoload options with large blobs: clean up, switch to on-demand.
Measurement discipline and observability without plugins
I measure reproducibly: same network conditions, same test path, warm and cold cache. I use DevTools locally, set realistic throttling profiles and monitor Waterfall, TTFB, LCP, CLS and INP. On the server, I look at access and error logs, compare response times per endpoint and check whether peak times correlate with cron runs. This allows me to identify bottlenecks without additional modules.
Performance budgets
I define upper limits, e.g. LCP < 1.8 s, HTML < 50 KB, total CSS < 100 KB, total JS < 150 KB, total images on the homepage < 600 KB. These budgets prevent weight from creeping in.
Summary and outlook
With a wp minimal setup I get an amazing amount of performance out of it: caching headers, image discipline, lean code, local resources, clever server tuning and a well-maintained database. For many projects, this is enough to significantly reduce loading times and boost rankings. For stores and very high traffic, there is room for targeted caching, but only after clean Basic work. If you measure consistently and proceed step by step, you can keep your site fast and low-maintenance. This keeps WordPress responsive, secure and easy to maintain - without any plugin ballast.


