<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Mecanik1337</title>
    <description>The latest articles on DEV Community by Mecanik1337 (@mecanik).</description>
    <link>https://dev.to/mecanik</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1250743%2F66c81bf6-877e-4930-9003-91653fd2453e.png</url>
      <title>DEV Community: Mecanik1337</title>
      <link>https://dev.to/mecanik</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mecanik"/>
    <language>en</language>
    <item>
      <title>Runtime encrypted strings: Part 1</title>
      <dc:creator>Mecanik1337</dc:creator>
      <pubDate>Tue, 06 Oct 2026 06:00:00 +0000</pubDate>
      <link>https://dev.to/mecanik-dev/runtime-encrypted-strings-part-1-5f90</link>
      <guid>https://dev.to/mecanik-dev/runtime-encrypted-strings-part-1-5f90</guid>
      <description>&lt;h2&gt;
  
  
  Runtime Encrypted Strings
&lt;/h2&gt;

&lt;p&gt;Today we will go through the basics of runtime encrypted strings, why do we need to encrypt our strings and learn how to create our own.&lt;/p&gt;

&lt;p&gt;In this article you will understand and learn:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What is runtime encryption and decryption&lt;/li&gt;
&lt;li&gt;Why do you need to encrypt your strings&lt;/li&gt;
&lt;li&gt;See how anybody can see your sensitive data&lt;/li&gt;
&lt;li&gt;Create your own custom encryption&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What is runtime encryption and decryption
&lt;/h2&gt;

&lt;p&gt;This refers to data encrypted and/or decrypted during the runtime of a program (software, application). The data can be of any type from memory blocks, network traffic, strings, etc.&lt;/p&gt;

&lt;p&gt;One of the most common methods used for this purpose is obfuscation (basic). The other (advanced) mechanisms involve mutation/virtualization of compiled code.&lt;/p&gt;

&lt;p&gt;Today we will focus on a mechanism using &lt;a href="https://en.wikipedia.org/wiki/XOR_cipher" rel="noopener noreferrer"&gt;XOR obfuscation&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why encrypt strings?
&lt;/h2&gt;

&lt;p&gt;The moment you run your software everything is visible in memory. This applies to your end users as well which means they can see everything.&lt;/p&gt;

&lt;p&gt;One of the first things an attacker will do is look for strings inside your software. This will allow him to understand everything about your software with minimal effort.&lt;/p&gt;

&lt;p&gt;If you are storing sensitive data (like passwords or licenses) it is crucial to not keep them in plain text. Keeping them in plain text will make the life of an attacker easy.&lt;/p&gt;

&lt;p&gt;There is a number of ways people can use to analyze your software. The most known and common methods are static and runtime analysis.&lt;/p&gt;

&lt;p&gt;Let’s have a look at a simple example using a console app:&lt;/p&gt;

&lt;p&gt;&lt;br&gt;
    &lt;br&gt;
    &lt;br&gt;
    &lt;br&gt;
    &lt;br&gt;
    &lt;br&gt;&lt;br&gt;
    &lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmecanik.dev%2Fcdn-cgi%2Fimagedelivery%2FxqiSCiPBXNEeBkfBRiRspQ%2F32e0c730-c260-456e-fda2-195b1d04dc00%2F1200x675" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmecanik.dev%2Fcdn-cgi%2Fimagedelivery%2FxqiSCiPBXNEeBkfBRiRspQ%2F32e0c730-c260-456e-fda2-195b1d04dc00%2F1200x675" width="834" height="452" alt="Sample non-encrypted 1"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;We compile this in Release mode (to avoid any debug information left inside). Let’s proceed and test the static and runtime analysis.&lt;/p&gt;

&lt;h3&gt;
  
  
  Static Analysis Test
&lt;/h3&gt;

&lt;p&gt;In static analysis the software does not need to execute. With that said, let’s open the sample in &lt;a href="https://ghidra-sre.org/" rel="noopener noreferrer"&gt;Ghidra&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;From the screenshot below you can see that the sample is compiled without any debug information:&lt;/p&gt;

&lt;p&gt;&lt;br&gt;
    &lt;br&gt;
    &lt;br&gt;
    &lt;br&gt;
    &lt;br&gt;
    &lt;br&gt;&lt;br&gt;
    &lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmecanik.dev%2Fcdn-cgi%2Fimagedelivery%2FxqiSCiPBXNEeBkfBRiRspQ%2Fb16393bd-d60a-4613-5644-a7f28c9afc00%2F1200x675" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmecanik.dev%2Fcdn-cgi%2Fimagedelivery%2FxqiSCiPBXNEeBkfBRiRspQ%2Fb16393bd-d60a-4613-5644-a7f28c9afc00%2F1200x675" width="1200" height="650" alt="Sample non-encrypted 1-1"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;If we search for strings you can see that all our sensitive information is visible:&lt;/p&gt;

&lt;p&gt;&lt;br&gt;
    &lt;br&gt;
    &lt;br&gt;
    &lt;br&gt;
    &lt;br&gt;
    &lt;br&gt;&lt;br&gt;
    &lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmecanik.dev%2Fcdn-cgi%2Fimagedelivery%2FxqiSCiPBXNEeBkfBRiRspQ%2Ff17e4ff8-60d4-4af9-ee3c-8e3ae949f300%2F1200x675" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmecanik.dev%2Fcdn-cgi%2Fimagedelivery%2FxqiSCiPBXNEeBkfBRiRspQ%2Ff17e4ff8-60d4-4af9-ee3c-8e3ae949f300%2F1200x675" width="1200" height="652" alt="Sample non-encrypted 1-2"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;Once you highlighted the string you can open the decompiler view and see all the relevant code:&lt;/p&gt;

&lt;p&gt;&lt;br&gt;
    &lt;br&gt;
    &lt;br&gt;
    &lt;br&gt;
    &lt;br&gt;
    &lt;br&gt;&lt;br&gt;
    &lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmecanik.dev%2Fcdn-cgi%2Fimagedelivery%2FxqiSCiPBXNEeBkfBRiRspQ%2Fcf6096ee-f879-4bd0-e3aa-7f796cb42a00%2F1200x675" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmecanik.dev%2Fcdn-cgi%2Fimagedelivery%2FxqiSCiPBXNEeBkfBRiRspQ%2Fcf6096ee-f879-4bd0-e3aa-7f796cb42a00%2F1200x675" width="1200" height="650" alt="Sample non-encrypted 1-3"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;Pretty sad eh? 😕 Imagine you worked on your amazing software for months, and you are ready to sell it.&lt;/p&gt;

&lt;p&gt;I think the rest is self-explanatory, but I’m sure you get the point.&lt;/p&gt;

&lt;p&gt;What’s even sadder is the fact that this is so simple that even a 12-year old can do it. (and some actually do it)&lt;/p&gt;

&lt;h3&gt;
  
  
  Runtime Analysis Test
&lt;/h3&gt;

&lt;p&gt;In runtime analysis the software needs to run (execute). This means we need to use a software to open the process and read it (normally a debugger).&lt;/p&gt;

&lt;p&gt;However, a debugger is not really needed for this purpose. We can simply download a free tool like &lt;a href="https://processhacker.sourceforge.io/" rel="noopener noreferrer"&gt;Process Hacker&lt;/a&gt; and open the process:&lt;/p&gt;

&lt;p&gt;&lt;br&gt;
    &lt;br&gt;
    &lt;br&gt;
    &lt;br&gt;
    &lt;br&gt;
    &lt;br&gt;&lt;br&gt;
    &lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmecanik.dev%2Fcdn-cgi%2Fimagedelivery%2FxqiSCiPBXNEeBkfBRiRspQ%2F3ac98faa-2fd4-470c-9c56-53d0616fb600%2F1200x675" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmecanik.dev%2Fcdn-cgi%2Fimagedelivery%2FxqiSCiPBXNEeBkfBRiRspQ%2F3ac98faa-2fd4-470c-9c56-53d0616fb600%2F1200x675" width="834" height="450" alt="Sample non-encrypted 2"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;That was rather simple right? And keep in mind that we haven’t even attached a debugger. A skilled and determined individual will use a debugger.&lt;/p&gt;

&lt;p&gt;When you attach a debugger you see much more, but that discussion is for another day.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating Runtime Encrypted Strings
&lt;/h2&gt;

&lt;p&gt;There are numerous ways you achieve this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Using a third party software like &lt;a href="https://vmpsoft.com/" rel="noopener noreferrer"&gt;VMProtect&lt;/a&gt;, &lt;a href="https://www.oreans.com/Themida.php" rel="noopener noreferrer"&gt;Themida&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Compile time string encryption like &lt;a href="https://github.com/JustasMasiulis/xorstr" rel="noopener noreferrer"&gt;xorstr&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Using custom methods&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The first 2 options might not suit your needs. There are many ups and downs for each of them, which we will not discuss at this point.&lt;/p&gt;

&lt;p&gt;One thing you need to understand is that popularity means risk. When you use stuff found randomly on Google, someone already knows about it.&lt;/p&gt;

&lt;p&gt;Most people developed a tool against your tool. It’s just the way things are. They do it for a challenge, or to steal your work, but they do it.&lt;/p&gt;

&lt;p&gt;With this in mind, you must go custom. You can create your own string encryption from basic to advanced level.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Plan
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Create an easy to use solution&lt;/li&gt;
&lt;li&gt;Keep strings encrypted at all times&lt;/li&gt;
&lt;li&gt;Decryption only when you need it&lt;/li&gt;
&lt;li&gt;Place the strings in random location (optional – not covered)&lt;/li&gt;
&lt;li&gt;Destroy the strings after using them (optional – not covered)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The Solution
&lt;/h3&gt;

&lt;p&gt;Start by defining our strings one by one as an array:&lt;/p&gt;

&lt;p&gt;&lt;br&gt;
    &lt;br&gt;
    &lt;br&gt;
    &lt;br&gt;
    &lt;br&gt;
    &lt;br&gt;&lt;br&gt;
    &lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmecanik.dev%2Fcdn-cgi%2Fimagedelivery%2FxqiSCiPBXNEeBkfBRiRspQ%2F9dc647fb-e92b-4fdd-9512-94489571d900%2F1200x675" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmecanik.dev%2Fcdn-cgi%2Fimagedelivery%2FxqiSCiPBXNEeBkfBRiRspQ%2F9dc647fb-e92b-4fdd-9512-94489571d900%2F1200x675" width="834" height="225" alt="Step 1"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;The array can hold an unlimited number of strings with a 256 length limit.&lt;/p&gt;

&lt;p&gt;I know this is a daunting task, especially if your strings are long. This is just for demonstration and later on we will create a more practical solution.&lt;/p&gt;

&lt;p&gt;The idea is to encrypt each character from the string. I will use a simple XOR encryption for this.&lt;/p&gt;

&lt;p&gt;Below you can see an example of how this would work:&lt;/p&gt;

&lt;p&gt;&lt;br&gt;
    &lt;br&gt;
    &lt;br&gt;
    &lt;br&gt;
    &lt;br&gt;
    &lt;br&gt;&lt;br&gt;
    &lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmecanik.dev%2Fcdn-cgi%2Fimagedelivery%2FxqiSCiPBXNEeBkfBRiRspQ%2F61f51e2b-a9a6-46e7-da6b-0fa703cccb00%2F1200x675" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmecanik.dev%2Fcdn-cgi%2Fimagedelivery%2FxqiSCiPBXNEeBkfBRiRspQ%2F61f51e2b-a9a6-46e7-da6b-0fa703cccb00%2F1200x675" width="834" height="450" alt="Step 2"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;The above has nothing complicated going on, it’s plain and simple yet quite powerful. You can use this inside a console application.&lt;/p&gt;

&lt;p&gt;After you compile and run, the result is unreadable bytes to the human eye:&lt;/p&gt;

&lt;p&gt;&lt;br&gt;
    &lt;br&gt;
    &lt;br&gt;
    &lt;br&gt;
    &lt;br&gt;
    &lt;br&gt;&lt;br&gt;
    &lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmecanik.dev%2Fcdn-cgi%2Fimagedelivery%2FxqiSCiPBXNEeBkfBRiRspQ%2Fdf20fa22-7c05-4a93-8bca-da81d1fc1e00%2F1200x675" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmecanik.dev%2Fcdn-cgi%2Fimagedelivery%2FxqiSCiPBXNEeBkfBRiRspQ%2Fdf20fa22-7c05-4a93-8bca-da81d1fc1e00%2F1200x675" width="834" height="450" alt="Step 3"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;There you have it, your own little software to create runtime encrypted strings. 😏&lt;/p&gt;

&lt;h3&gt;
  
  
  The Result
&lt;/h3&gt;

&lt;p&gt;I’s time to put our solution into practice. Let’s create another sample for this purpose and add our code:&lt;/p&gt;

&lt;p&gt;&lt;br&gt;
    &lt;br&gt;
    &lt;br&gt;
    &lt;br&gt;
    &lt;br&gt;
    &lt;br&gt;&lt;br&gt;
    &lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmecanik.dev%2Fcdn-cgi%2Fimagedelivery%2FxqiSCiPBXNEeBkfBRiRspQ%2Fca5b3dff-2934-4d1a-7ab9-f78348848200%2F1200x675" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmecanik.dev%2Fcdn-cgi%2Fimagedelivery%2FxqiSCiPBXNEeBkfBRiRspQ%2Fca5b3dff-2934-4d1a-7ab9-f78348848200%2F1200x675" width="834" height="646" alt="Step 4"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;Notice 2 important things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I’ve left some strings in plain text so you can see the difference&lt;/li&gt;
&lt;li&gt;The decryption functions needs the length (more on this later)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We compile the above in Release mode and run it. The new Sample is working normally:&lt;/p&gt;

&lt;p&gt;&lt;br&gt;
    &lt;br&gt;
    &lt;br&gt;
    &lt;br&gt;
    &lt;br&gt;
    &lt;br&gt;&lt;br&gt;
    &lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmecanik.dev%2Fcdn-cgi%2Fimagedelivery%2FxqiSCiPBXNEeBkfBRiRspQ%2F52e55e99-3f85-414c-5bb4-096b4b703c00%2F1200x675" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmecanik.dev%2Fcdn-cgi%2Fimagedelivery%2FxqiSCiPBXNEeBkfBRiRspQ%2F52e55e99-3f85-414c-5bb4-096b4b703c00%2F1200x675" width="834" height="250" alt="Step 5"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;If we open the new Sample software in IDA (or Ghidra) the strings we encrypted are not visible:&lt;/p&gt;

&lt;p&gt;&lt;br&gt;
    &lt;br&gt;
    &lt;br&gt;
    &lt;br&gt;
    &lt;br&gt;
    &lt;br&gt;&lt;br&gt;
    &lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmecanik.dev%2Fcdn-cgi%2Fimagedelivery%2FxqiSCiPBXNEeBkfBRiRspQ%2Fc86cee8d-7944-45d9-718c-cecc111d5a00%2F1200x675" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmecanik.dev%2Fcdn-cgi%2Fimagedelivery%2FxqiSCiPBXNEeBkfBRiRspQ%2Fc86cee8d-7944-45d9-718c-cecc111d5a00%2F1200x675" width="834" height="450" alt="Step 6"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;I’ve mentioned that there are some string intentionally left plain in this sample. The reason why is, so we can follow them to see the code:&lt;/p&gt;

&lt;p&gt;&lt;br&gt;
    &lt;br&gt;
    &lt;br&gt;
    &lt;br&gt;
    &lt;br&gt;
    &lt;br&gt;&lt;br&gt;
    &lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmecanik.dev%2Fcdn-cgi%2Fimagedelivery%2FxqiSCiPBXNEeBkfBRiRspQ%2F01ab1fdd-f28e-4553-4838-aea18eb36d00%2F1200x675" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmecanik.dev%2Fcdn-cgi%2Fimagedelivery%2FxqiSCiPBXNEeBkfBRiRspQ%2F01ab1fdd-f28e-4553-4838-aea18eb36d00%2F1200x675" width="710" height="675" alt="Step 7"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;I had to scroll down to reach the text in the above image. You can see how different the compiled code is.&lt;/p&gt;

&lt;p&gt;We solved the static analysis problem, let’s move on to runtime.&lt;/p&gt;

&lt;p&gt;Open it in Process Hacker:&lt;/p&gt;

&lt;p&gt;&lt;br&gt;
    &lt;br&gt;
    &lt;br&gt;
    &lt;br&gt;
    &lt;br&gt;
    &lt;br&gt;&lt;br&gt;
    &lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmecanik.dev%2Fcdn-cgi%2Fimagedelivery%2FxqiSCiPBXNEeBkfBRiRspQ%2F48adaff6-5972-42af-2571-aed2e91d7600%2F1200x675" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmecanik.dev%2Fcdn-cgi%2Fimagedelivery%2FxqiSCiPBXNEeBkfBRiRspQ%2F48adaff6-5972-42af-2571-aed2e91d7600%2F1200x675" width="834" height="450" alt="Step 8"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;Voila! We solved the runtime analysis problem as well 😎&lt;/p&gt;

&lt;h2&gt;
  
  
  More on encrypted strings
&lt;/h2&gt;

&lt;p&gt;The above example is not very practical. Defining each string manually is a daunting task, as well as specifying the length of the string each time.&lt;/p&gt;

&lt;p&gt;Ideally we would need the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reading a text file for strings&lt;/li&gt;
&lt;li&gt;Writing to a text file the resulted strings&lt;/li&gt;
&lt;li&gt;Adding the &lt;a href="https://en.cppreference.com/w/cpp/language/escape" rel="noopener noreferrer"&gt;Escape sequences&lt;/a&gt; to strings to avoid specifying the length each time.&lt;/li&gt;
&lt;li&gt;Add more complex XOR or any other method (optional)&lt;/li&gt;
&lt;li&gt;Place the strings on random locations (optional)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I have prepared a nice solution for you to play with. You can test everything written in this article and also have your own ready to use tool to make runtime encrypted strings.&lt;/p&gt;

&lt;p&gt;It includes 4 projects:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;RuntimeStringEcryptor&lt;/strong&gt; which reads from a text file strings, encrypts them and then writes them to another text file.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sample&lt;/strong&gt; is the plain simple console used to demonstrate with IDA.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SampleEncryptedStrings&lt;/strong&gt; is the simple console with encrypted strings to demonstrate with IDA.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SimpleRuntimeStringEncryption&lt;/strong&gt; is the initial playground where you can test this method.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Notes:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If you don’t add escape sequence, the decryption will not know when to “stop”. The result being in gibberish/null data until it reaches the defined array size.&lt;/li&gt;
&lt;li&gt;Make sure you change the XOR keys I have used in my example.&lt;/li&gt;
&lt;li&gt;Avoid using the same words multiple times. They will generate the same bytes and it’s a risk of being detected.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Download
&lt;/h2&gt;

&lt;p&gt;To download the ready to use solution, please consider supporting this blog 😘&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.patreon.com/posts/38759949" rel="nofollow noopener noreferrer"&gt;&lt;br&gt;
&lt;img width="251" height="51"&gt;
        src="https://mecanik.dev/cdn-cgi/imagedelivery/xqiSCiPBXNEeBkfBRiRspQ/e7b91857-3fd7-474f-3b11-020258f32b00/350x197" class="img-fluid mx-auto" alt="Become a Patron" &amp;gt;&lt;br&gt;
&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Related reading:&lt;/strong&gt; &lt;a href="https://mecanik.dev/en/posts/convert-dos-and-nt-paths-using-rtl-functions/" rel="noopener noreferrer"&gt;Convert DOS and NT paths using RTL functions&lt;/a&gt;, &lt;a href="https://mecanik.dev/en/posts/how-to-write-mini-dump-on-software-crash/" rel="noopener noreferrer"&gt;How to write Mini Dump on software crash&lt;/a&gt;, &lt;a href="https://mecanik.dev/en/posts/learn-programming-fundamentals-choosing-the-right-language/" rel="noopener noreferrer"&gt;Learn Programming Fundamentals: Choosing the Right Language&lt;/a&gt; and &lt;a href="https://mecanik.dev/en/posts/hire-cpp-developer-rates-specialisms-vetting/" rel="noopener noreferrer"&gt;Hire a C++ Developer: Rates, Specialisms and Vetting&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>c</category>
      <category>cpp</category>
      <category>linux</category>
      <category>windows</category>
    </item>
    <item>
      <title>DeepSeek R1 vs. OpenAI o3-mini: Which API is Best?</title>
      <dc:creator>Mecanik1337</dc:creator>
      <pubDate>Mon, 05 Oct 2026 18:00:00 +0000</pubDate>
      <link>https://dev.to/mecanik-dev/deepseek-r1-vs-openai-o3-mini-which-api-is-best-2nm1</link>
      <guid>https://dev.to/mecanik-dev/deepseek-r1-vs-openai-o3-mini-which-api-is-best-2nm1</guid>
      <description>&lt;p&gt;Choosing between DeepSeek R1 vs OpenAI o3-mini is a critical decision for developers integrating reasoning APIs into software applications in 2026. When it comes to reasoning APIs, these are the two strongest candidates most teams end up weighing. Both models excel at complex tasks, code generation, mathematical analysis, and structured logic. However, they operate on different pricing structures, reasoning token methods, latency patterns, and structured data validation limits. This guide compares the two in detail to help you choose the best API for your developer workflows.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Understand reasoning models&lt;/strong&gt;; reasoning models utilise "thinking tokens" to solve problems before returning a response, improving accuracy on logical tasks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DeepSeek R1 is highly cost-effective&lt;/strong&gt;; R1 offers open-source weights and extremely low API costs, making it ideal for high-volume execution.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OpenAI o3-mini delivers lower latency&lt;/strong&gt;; o3-mini excels at rapid, real-time responses and features robust structured JSON-schema support.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Evaluate data portability&lt;/strong&gt;; R1 can be hosted on your own cloud infrastructure, preventing vendor lock-in, while o3-mini is hosted exclusively on OpenAI.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Select based on task requirements&lt;/strong&gt;; use o3-mini for interactive, real-time web applications, and R1 for bulk analytical workflows and offline data processing.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Core Concept of Reasoning Models
&lt;/h2&gt;

&lt;p&gt;Unlike standard chat completion models, reasoning models are trained to think step by step before outputting answers.&lt;/p&gt;

&lt;p&gt;This reasoning process utilises specialised "thinking tokens." The model generates internal steps to cross-examine its assumptions, debug code, and analyse syntax. While this process improves the quality of responses on complex logical tasks, it increases response latency and token costs. Understanding how to manage these context sizes is essential for budgeting. To see how standard APIs differ from reasoning ones, read our guide on &lt;a href="https://mecanik.dev/en/posts/building-an-ai-chatbot-with-the-openai-api/" rel="noopener noreferrer"&gt;building an OpenAI API chatbot&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Latency vs. Reasoning Depth
&lt;/h2&gt;

&lt;p&gt;In production, latency is a critical consideration. If your application requires real-time user interaction, slow API responses will harm the user experience.&lt;/p&gt;

&lt;p&gt;OpenAI's o3-mini is optimised for speed. It returns complex reasoning answers in a fraction of the time required by larger models, making it ideal for interactive coding tools. In a head-to-head speed test, o3-mini comes out faster, while DeepSeek R1 prioritises reasoning depth. It writes longer internal reasoning steps, which can result in longer response times. To inspect how to handle edge compute limits and latency, read our comparison of &lt;a href="https://mecanik.dev/en/posts/cloudflare-workers-vs-aws-lambda-2026/" rel="noopener noreferrer"&gt;Cloudflare Workers vs AWS Lambda&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Structured Outputs and JSON Parsing
&lt;/h2&gt;

&lt;p&gt;When integrating AI into software workflows, receiving unstructured text is problematic. You must ensure the model returns structured data, such as JSON schemas, to integrate with your database.&lt;/p&gt;

&lt;p&gt;OpenAI o3-mini supports structured outputs with strict JSON schemas. This feature guarantees that the API response matches your specified JSON schema exactly, eliminating parsing errors. DeepSeek R1 also supports JSON formats, but developers must write clear system instructions and handle validation checks manually. If you are building database integrations, we suggest linking these APIs to edge databases; see &lt;a href="https://mecanik.dev/en/posts/cloudflare-d1-build-a-serverless-sql-database-on-the-edge/" rel="noopener noreferrer"&gt;Cloudflare D1 serverless database setup&lt;/a&gt; for details.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pricing and Cost Optimisation
&lt;/h2&gt;

&lt;p&gt;API usage costs are a primary consideration when scaling AI applications. The table below highlights the key pricing differences between the two APIs.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Model API&lt;/th&gt;
&lt;th&gt;Input Cost (per 1M tokens)&lt;/th&gt;
&lt;th&gt;Output Cost (per 1M tokens)&lt;/th&gt;
&lt;th&gt;Hosting Flexibility&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;OpenAI o3-mini&lt;/td&gt;
&lt;td&gt;Higher&lt;/td&gt;
&lt;td&gt;Moderate&lt;/td&gt;
&lt;td&gt;Hosted only (proprietary)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DeepSeek R1&lt;/td&gt;
&lt;td&gt;Extremely Low&lt;/td&gt;
&lt;td&gt;Extremely Low&lt;/td&gt;
&lt;td&gt;Portable (open weights)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;DeepSeek R1 is highly cost-effective, providing reasoning capabilities at a fraction of the cost of proprietary alternatives. Furthermore, since R1 weights are open, you can host the model on your own hardware or deploy it to edge runtimes; see our &lt;a href="https://mecanik.dev/en/posts/cloudflare-workers-ai-tutorial/" rel="noopener noreferrer"&gt;Cloudflare Workers AI tutorial&lt;/a&gt; to learn how to deploy models serverless.&lt;/p&gt;

&lt;h2&gt;
  
  
  How the Two Reasoning APIs Compare at a Glance
&lt;/h2&gt;

&lt;p&gt;The headline choice comes down to a handful of dimensions that actually affect an integration: how much context each model accepts, how it handles structured data, where it can run, and what a request costs. The table below summarises the practical differences. Treat the specific figures as illustrative snapshots. Published limits and rates for both APIs change frequently, so confirm the current numbers in each provider's documentation before you commit.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dimension&lt;/th&gt;
&lt;th&gt;OpenAI o3-mini&lt;/th&gt;
&lt;th&gt;DeepSeek R1&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Context window (typical)&lt;/td&gt;
&lt;td&gt;~200K tokens&lt;/td&gt;
&lt;td&gt;~64K tokens&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Max output per request&lt;/td&gt;
&lt;td&gt;~100K tokens&lt;/td&gt;
&lt;td&gt;~8K–32K tokens&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Structured outputs&lt;/td&gt;
&lt;td&gt;Native strict JSON schema&lt;/td&gt;
&lt;td&gt;JSON via prompting + manual validation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reasoning-effort control&lt;/td&gt;
&lt;td&gt;Adjustable (low/medium/high)&lt;/td&gt;
&lt;td&gt;Fixed reasoning behaviour&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hosting&lt;/td&gt;
&lt;td&gt;OpenAI cloud only&lt;/td&gt;
&lt;td&gt;Hosted API or self-hosted (open weights)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Relative latency&lt;/td&gt;
&lt;td&gt;Lower&lt;/td&gt;
&lt;td&gt;Higher (longer reasoning traces)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Relative token price&lt;/td&gt;
&lt;td&gt;Higher&lt;/td&gt;
&lt;td&gt;Substantially lower&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best-fit workload&lt;/td&gt;
&lt;td&gt;Interactive, real-time tools&lt;/td&gt;
&lt;td&gt;High-volume, batch analysis&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Two rows deserve extra attention. o3-mini exposes a reasoning-effort setting, so you can dial thinking down for simple calls and up for hard ones, a direct lever on both latency and cost. R1's open weights, by contrast, mean the same model can run inside your own network, which matters for data-residency and compliance requirements that a hosted-only API cannot satisfy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Working Out the Cost per 1,000 Calls
&lt;/h2&gt;

&lt;p&gt;Per-million-token rates are hard to reason about in isolation, so it helps to work a realistic scenario end to end. Imagine a classification service that enriches each support ticket: roughly &lt;strong&gt;800 input tokens&lt;/strong&gt; of prompt and context, and &lt;strong&gt;1,200 output tokens&lt;/strong&gt; per reply, of which perhaps 900 are internal thinking tokens and 300 the visible answer. Reasoning models bill those thinking tokens at the standard output rate, so they count in full.&lt;/p&gt;

&lt;p&gt;Using illustrative published rates (o3-mini around $1.10 input and $4.40 output per million tokens; R1 around $0.55 input and $2.19 output per million), the arithmetic works out as follows:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Step&lt;/th&gt;
&lt;th&gt;OpenAI o3-mini&lt;/th&gt;
&lt;th&gt;DeepSeek R1&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Input: 800 tokens&lt;/td&gt;
&lt;td&gt;$0.00088&lt;/td&gt;
&lt;td&gt;$0.00044&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Output: 1,200 tokens&lt;/td&gt;
&lt;td&gt;$0.00528&lt;/td&gt;
&lt;td&gt;$0.00263&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cost per call&lt;/td&gt;
&lt;td&gt;~$0.0062&lt;/td&gt;
&lt;td&gt;~$0.0031&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cost per 1,000 calls&lt;/td&gt;
&lt;td&gt;~$6.16&lt;/td&gt;
&lt;td&gt;~$3.07&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cost at 1M calls/month&lt;/td&gt;
&lt;td&gt;~$6,160&lt;/td&gt;
&lt;td&gt;~$3,070&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;At this shape of workload the hosted R1 API lands at roughly half the running cost of o3-mini. The gap widens as output tokens grow, because reasoning-heavy prompts spend most of their budget on the more expensive output side. The lesson is to estimate output tokens, thinking included, rather than input, since that is where reasoning-model bills are won or lost. Capping maximum output tokens and lowering reasoning effort on easy calls are the two most effective controls.&lt;/p&gt;

&lt;p&gt;Self-hosting R1 changes the equation again: you swap per-token fees for GPU rental. A high-memory GPU instance capable of serving the full model tends to run into the low thousands of pounds per month, so self-hosting only beats the API once sustained throughput is high enough to keep that hardware busy. Below that break-even point, the managed API is cheaper and far less operational work.&lt;/p&gt;

&lt;h2&gt;
  
  
  Choosing by Workload, Not by Winner
&lt;/h2&gt;

&lt;p&gt;Neither model is universally "better"; the right pick follows the shape of the job.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Choose OpenAI o3-mini when&lt;/strong&gt; the interaction is user-facing and latency is visible: coding assistants, chat features, autocomplete, or anything where a person waits for the response. Its native strict JSON schema also makes it the safer choice when a malformed response would break a downstream system, such as a function-calling agent or a database write. The adjustable reasoning effort lets one integration serve both quick and hard queries without swapping models.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Choose DeepSeek R1 when&lt;/strong&gt; volume is high and latency is hidden: overnight batch jobs, document enrichment, bulk classification, dataset labelling, or offline analysis where throughput and unit cost matter more than a second or two of delay. It is also the pragmatic choice under strict data-governance rules, because the open weights let you keep every token inside infrastructure you control.&lt;/p&gt;

&lt;p&gt;Many production stacks end up using both: a fast hosted model on the interactive path and a cheaper, self-hostable model on the batch path, with a routing layer that sends each request to the model that fits. That hybrid pattern captures most of the cost saving without sacrificing the responsiveness users notice.&lt;/p&gt;

&lt;h2&gt;
  
  
  Total Cost of Ownership and Switching Costs
&lt;/h2&gt;

&lt;p&gt;Sticker price is only part of the total cost of ownership. Because both APIs speak a broadly OpenAI-compatible request format, moving a prompt from one to the other is usually a matter of changing the endpoint, key, and model name rather than rewriting application logic. That keeps switching costs low and is a strong argument for not hard-coding a single provider. The larger migration effort sits elsewhere: strict-schema features and reasoning-effort parameters are provider-specific, so any code that depends on them needs a fallback path when you move to a model that lacks them.&lt;/p&gt;

&lt;p&gt;Factor in the softer costs too. A hosted API adds no operational burden but exposes you to rate limits, pricing changes, and regional availability. Self-hosting removes those risks but adds GPU provisioning, scaling, patching, and monitoring, all real engineering time that belongs in the budget. Abstracting the model call behind a thin internal interface from day one is the cheapest insurance: it lets you test the two APIs against each other on your own traffic and switch whenever price or performance shifts, which for fast-moving reasoning models it inevitably will.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Reasoning models use internal thinking tokens to solve logical problems, outperforming standard chat models.&lt;/li&gt;
&lt;li&gt;OpenAI o3-mini is optimised for low-latency, real-time web applications requiring structured JSON formats.&lt;/li&gt;
&lt;li&gt;DeepSeek R1 is highly cost-effective and portable, allowing self-hosting to prevent vendor lock-in.&lt;/li&gt;
&lt;li&gt;Choose o3-mini for interactive development assistants; choose R1 for high-volume offline data analysis.&lt;/li&gt;
&lt;li&gt;Manage reasoning token sizes carefully to prevent unexpected API costs in production.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Integrate Reasoning Models into Your Stack
&lt;/h2&gt;

&lt;p&gt;Integrating advanced reasoning APIs requires careful prompt engineering, error handling, and hosting configurations. Mecanik provides professional &lt;a href="https://mecanik.dev/en/ai-integration-services/" rel="noopener noreferrer"&gt;AI integration services&lt;/a&gt; and custom setups through our &lt;a href="https://mecanik.dev/en/openai-api-integration/" rel="noopener noreferrer"&gt;OpenAI API integration service&lt;/a&gt;. We construct fast, secure AI pipelines tailored to your business. Contact us today to discuss your next project.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Related reading:&lt;/strong&gt; &lt;a href="https://mecanik.dev/en/posts/claude-opus-4-8-vs-gpt-5-api/" rel="noopener noreferrer"&gt;Claude Opus 4.8 vs. OpenAI GPT-5: Which API is Best?&lt;/a&gt;, &lt;a href="https://mecanik.dev/en/posts/ai-integration-cost-enterprise-budgeting-guide/" rel="noopener noreferrer"&gt;AI Integration Cost: 2026 Enterprise Budgeting Guide&lt;/a&gt;, &lt;a href="https://mecanik.dev/en/posts/claude-fable-5-hybrid-reasoning-api/" rel="noopener noreferrer"&gt;Claude Fable 5 Hybrid Reasoning: Thinking vs. Speed Modes&lt;/a&gt; and &lt;a href="https://mecanik.dev/en/posts/reduce-llm-latency-prompt-caching/" rel="noopener noreferrer"&gt;How to Reduce LLM Latency: Caching and Edge Strategies&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Frequently Asked Questions (FAQ)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What is the difference between a reasoning model and a standard model?&lt;/strong&gt;&lt;br&gt;
Reasoning models use internal thinking tokens to analyse problems and debug logical steps before outputting a response, whereas standard models predict the next token immediately.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I host DeepSeek R1 on my own servers?&lt;/strong&gt;&lt;br&gt;
Yes. &lt;a href="https://www.deepseek.com/" rel="noopener noreferrer"&gt;DeepSeek R1&lt;/a&gt; is an open-source model with public weights, allowing you to self-host it on your own GPU infrastructure or deploy it on serverless runtimes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does OpenAI o3-mini support strict JSON schemas?&lt;/strong&gt;&lt;br&gt;
Yes. &lt;a href="https://openai.com/" rel="noopener noreferrer"&gt;OpenAI&lt;/a&gt;'s API supports structured outputs, guaranteeing that the model's output conforms exactly to the JSON schema you define in the API call.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How does thinking token usage impact API costs?&lt;/strong&gt;&lt;br&gt;
Thinking tokens are billed as input and output tokens. Because the model must write out its internal reasoning steps, a single query uses more tokens than a standard API query.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Which model is better for code generation?&lt;/strong&gt;&lt;br&gt;
Both are excellent. OpenAI o3-mini is faster and more interactive, while DeepSeek R1 often provides deeper logic analysis on complex, multi-file software tasks.&lt;/p&gt;

</description>
      <category>serverless</category>
      <category>openai</category>
      <category>deepseek</category>
      <category>api</category>
    </item>
    <item>
      <title>Deploying Llama 3 on the Edge with Cloudflare Workers AI</title>
      <dc:creator>Mecanik1337</dc:creator>
      <pubDate>Mon, 05 Oct 2026 06:00:00 +0000</pubDate>
      <link>https://dev.to/mecanik-dev/deploying-llama-3-on-the-edge-with-cloudflare-workers-ai-2nf9</link>
      <guid>https://dev.to/mecanik-dev/deploying-llama-3-on-the-edge-with-cloudflare-workers-ai-2nf9</guid>
      <description>&lt;p&gt;This Cloudflare Workers AI tutorial shows you how to deploy and run machine learning models directly on Cloudflare's global edge network. With &lt;a href="https://developers.cloudflare.com/workers-ai/" rel="noopener noreferrer"&gt;Cloudflare Workers AI&lt;/a&gt;, you can execute Large Language Models (LLMs), text translation, image generation, and audio transcription close to your users without managing complex GPU servers. The steps below cover how to configure Wrangler, write a fetch handler, run a Llama model, and optimise API costs at the edge.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Run AI models serverless&lt;/strong&gt;; Cloudflare Workers AI manages the underlying GPU infrastructure, billing you only for active compute.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Configure bindings in wrangler.toml&lt;/strong&gt;; link your worker directly to the AI binding without managing API keys.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Write a fetch handler&lt;/strong&gt; to receive user requests, execute the model, and stream JSON responses.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Select optimised models&lt;/strong&gt; from Cloudflare's catalogue (such as Llama 3, Whisper, or Stable Diffusion) to balance speed and accuracy.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Silo billing and rate limits&lt;/strong&gt; to protect your endpoint from high-token cost abuse in production.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why Run AI Models on the Edge?
&lt;/h2&gt;

&lt;p&gt;Traditionally, integrating AI features required calling external APIs (like OpenAI) or hosting open-source models on expensive cloud servers. &lt;/p&gt;

&lt;p&gt;Calling external APIs presents latency and data privacy concerns. Running your own GPU servers introduces maintenance challenges and scales poorly. Cloudflare Workers AI resolves this dilemma. The platform hosts open-source models on GPUs deployed across Cloudflare's global network. Your code runs as a lightweight Worker, executing models close to your users with near-zero latency. For an introduction to building basic edge structures, check our guide on &lt;a href="https://mecanik.dev/en/posts/building-a-serverless-api-with-cloudflare-workers/" rel="noopener noreferrer"&gt;building a serverless API with Cloudflare Workers&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before you begin, make sure you have the following in place:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A Cloudflare account&lt;/strong&gt; with Workers enabled. The free plan includes a daily inference allocation, which is more than enough to follow this guide.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Node.js 18 or newer&lt;/strong&gt; installed locally, so you can run the tooling and the local development server.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Wrangler, the Workers CLI, installed and authenticated.&lt;/strong&gt; Install it with &lt;code&gt;npm install -g wrangler&lt;/code&gt;, then run &lt;code&gt;wrangler login&lt;/code&gt; to link it to your account.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Basic familiarity with JavaScript&lt;/strong&gt; and the &lt;code&gt;fetch&lt;/code&gt; request/response model that every Worker is built around.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you are starting from a blank slate, scaffold a project with the create-cloudflare (C3) tool. It generates a ready-to-deploy Worker, a &lt;code&gt;wrangler.toml&lt;/code&gt;, and a sensible &lt;code&gt;compatibility_date&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm create cloudflare@latest my-edge-ai
&lt;span class="nb"&gt;cd &lt;/span&gt;my-edge-ai
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Choose the "Hello World" Worker template when prompted. That gives you a clean starting point to which you can add the AI binding in the next step.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Configuring wrangler.toml
&lt;/h2&gt;

&lt;p&gt;To access AI models, you first need to define the AI binding in your project's configuration file.&lt;/p&gt;

&lt;p&gt;Open your &lt;code&gt;wrangler.toml&lt;/code&gt; (or &lt;code&gt;wrangler.json&lt;/code&gt;) and add the following block:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="nn"&gt;[ai]&lt;/span&gt;
&lt;span class="py"&gt;binding&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"AI"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This binding makes the AI service available on the environment argument (&lt;code&gt;env.AI&lt;/code&gt;) in your worker code. You do not need to manage API keys, configure endpoints, or deal with connection strings. Wrangler handles the authentication automatically when you deploy.&lt;/p&gt;

&lt;p&gt;A complete &lt;code&gt;wrangler.toml&lt;/code&gt; for this project looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="py"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"my-edge-ai"&lt;/span&gt;
&lt;span class="py"&gt;main&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"src/index.js"&lt;/span&gt;
&lt;span class="py"&gt;compatibility_date&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"2025-01-01"&lt;/span&gt;

&lt;span class="nn"&gt;[ai]&lt;/span&gt;
&lt;span class="py"&gt;binding&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"AI"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;compatibility_date&lt;/code&gt; matters: it pins runtime behaviour so future platform changes cannot silently alter how your Worker runs. Omit it and deployment fails with a configuration error, which is one of the most common first-run stumbles.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Writing the Worker Code
&lt;/h2&gt;

&lt;p&gt;Once the binding is configured, you can call the AI service from your &lt;code&gt;fetch&lt;/code&gt; handler. The example below shows how to receive a JSON payload containing a user prompt and generate a text completion using Llama 3.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;method&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Method not allowed&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;405&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;prompt&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Missing prompt&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;400&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="c1"&gt;// Call the model using the AI binding&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AI&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@cf/meta/llama-3-8b-instruct&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;max_tokens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;256&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;

      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This simple structure allows you to build text summarisers, sentiment analysis tools, or content generators. If you want to connect these features to your database, you can bind to a serverless SQL database; see &lt;a href="https://mecanik.dev/en/posts/cloudflare-d1-build-a-serverless-sql-database-on-the-edge/" rel="noopener noreferrer"&gt;Cloudflare D1 database setup&lt;/a&gt; for details.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using the chat message format
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;prompt&lt;/code&gt; field is convenient for one-shot completions, but conversational models behave best with a structured &lt;code&gt;messages&lt;/code&gt; array. This lets you set a system instruction that shapes the model's tone and keep it separate from the user's input:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;messages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;system&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;You are a concise technical assistant.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;prompt&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AI&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@cf/meta/llama-3-8b-instruct&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;max_tokens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;512&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Text models return the generated text on the `response` property&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;answer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that text-generation models wrap their output in a &lt;code&gt;response&lt;/code&gt; field, so the completed text lives at &lt;code&gt;response.response&lt;/code&gt; rather than at the top level. This catches out many first-time users, who log the raw object and see an unexpected shape.&lt;/p&gt;

&lt;h2&gt;
  
  
  Choosing the Right Model
&lt;/h2&gt;

&lt;p&gt;Cloudflare's catalogue includes dozens of models, and choosing well is a trade-off between speed, quality, and cost. Smaller models reply faster and consume fewer resources; larger models reason better but cost more per request. The table below compares a few popular text-generation options.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;Best for&lt;/th&gt;
&lt;th&gt;Relative speed&lt;/th&gt;
&lt;th&gt;Relative cost&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@cf/meta/llama-3-8b-instruct&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;General chat, summarisation&lt;/td&gt;
&lt;td&gt;Fast&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@cf/meta/llama-3.1-70b-instruct&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Complex reasoning, longer answers&lt;/td&gt;
&lt;td&gt;Slower&lt;/td&gt;
&lt;td&gt;Higher&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@cf/mistral/mistral-7b-instruct-v0.2&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Lightweight instructions, drafts&lt;/td&gt;
&lt;td&gt;Fast&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@cf/meta/llama-guard-3-8b&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Moderating and classifying content&lt;/td&gt;
&lt;td&gt;Fast&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;As a rule of thumb, start with an 8B model such as Llama 3 8B Instruct. It handles the majority of summarisation, classification, and chat workloads at a fraction of the latency and cost of a 70B model. Only move up to a larger model once your own evaluations show the smaller one genuinely falling short.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Streaming Responses for Better User Experience
&lt;/h2&gt;

&lt;p&gt;For chat applications, waiting for the full response to generate can result in poor user experience. &lt;/p&gt;

&lt;p&gt;You can configure the AI binding to stream the response token by token as it generates. To achieve this, pass &lt;code&gt;stream: true&lt;/code&gt; in your request options. The worker will return a &lt;code&gt;ReadableStream&lt;/code&gt; that you can forward directly to the browser client, creating a fast, interactive chat interface. To compare this edge runtime approach with traditional cloud hosting, read our comparison of &lt;a href="https://mecanik.dev/en/posts/cloudflare-workers-vs-aws-lambda-2026/" rel="noopener noreferrer"&gt;Cloudflare Workers vs AWS Lambda&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Here is a complete streaming handler. Rather than returning parsed JSON, you forward the stream to the client with the correct &lt;code&gt;content-type&lt;/code&gt; so the browser can consume it as Server-Sent Events:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;prompt&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;stream&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AI&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@cf/meta/llama-3-8b-instruct&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;max_tokens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;512&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;content-type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text/event-stream&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The key difference from the non-streaming version is the response itself: you pass the stream straight into &lt;code&gt;new Response()&lt;/code&gt; and set &lt;code&gt;content-type&lt;/code&gt; to &lt;code&gt;text/event-stream&lt;/code&gt;. Wrap a stream in &lt;code&gt;Response.json()&lt;/code&gt; instead and it will not serialise correctly, so the client receives an empty body.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing and Deploying Your Worker
&lt;/h2&gt;

&lt;p&gt;With the binding and handler in place, run the Worker locally before you ship it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx wrangler dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because inference runs on Cloudflare's GPUs rather than on your machine, the AI binding reaches out to the network even during local development. Wrangler manages this for you, but it does mean local testing needs connectivity and a valid login to work.&lt;/p&gt;

&lt;p&gt;Send a test request with &lt;code&gt;curl&lt;/code&gt; while &lt;code&gt;wrangler dev&lt;/code&gt; is running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://localhost:8787 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"prompt": "Summarise the benefits of edge computing in one sentence."}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once you are happy with the output, deploy to the global network:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx wrangler deploy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Wrangler uploads your Worker and returns a &lt;code&gt;*.workers.dev&lt;/code&gt; URL. Your endpoint is now live in every Cloudflare data centre, and each request is routed to the location closest to the user automatically.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common Pitfalls and Troubleshooting
&lt;/h2&gt;

&lt;p&gt;A handful of issues recur when teams first deploy inference at the edge. Knowing the fix in advance saves hours of debugging.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;Cannot read properties of undefined (reading 'run')&lt;/code&gt;&lt;/strong&gt; — the &lt;code&gt;env.AI&lt;/code&gt; binding is undefined. This almost always means the &lt;code&gt;[ai]&lt;/code&gt; block is missing from &lt;code&gt;wrangler.toml&lt;/code&gt;, or you edited the file but did not restart &lt;code&gt;wrangler dev&lt;/code&gt; (or redeploy). Confirm the binding name matches exactly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;No such model&lt;/code&gt; or a 400 error on &lt;code&gt;run&lt;/code&gt;&lt;/strong&gt; — the model identifier is wrong. Model names are case-sensitive and must include the full path, for example &lt;code&gt;@cf/meta/llama-3-8b-instruct&lt;/code&gt;. Copy them from the model catalogue rather than typing from memory.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Empty or malformed streamed responses&lt;/strong&gt; — you returned the stream through &lt;code&gt;Response.json()&lt;/code&gt; instead of &lt;code&gt;new Response(stream, ...)&lt;/code&gt;. Streams must be forwarded, not serialised.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Capacity or 429 errors under load&lt;/strong&gt; — the model is temporarily saturated or you have hit an account limit. Add a short retry with back-off, and consider a smaller model for bursts of traffic.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Truncated answers&lt;/strong&gt; — the reply stops mid-sentence because &lt;code&gt;max_tokens&lt;/code&gt; is too low. Raise the limit, but remember that larger values increase both latency and cost.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If a request fails silently, watch the live logs with &lt;code&gt;npx wrangler tail&lt;/code&gt; while you send a test request. It streams runtime errors and &lt;code&gt;console.log&lt;/code&gt; output from the deployed Worker, which is the quickest way to see what the model actually returned.&lt;/p&gt;

&lt;h2&gt;
  
  
  Optimising Production Costs and Security
&lt;/h2&gt;

&lt;p&gt;While Workers AI is highly cost-effective, running model inference in production requires careful controls.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Implement Rate Limiting&lt;/strong&gt;: Limit how often a client can call your endpoint. GPU compute costs scale with usage.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sanitise Prompts&lt;/strong&gt;: Validate inputs to prevent injection attacks and ensure the model outputs stay on brand.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Silo Context Size&lt;/strong&gt;: Keep prompt histories short. Sending massive context buffers on each call increases token processing costs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For a detailed look at context management, check our guide on &lt;a href="https://mecanik.dev/en/posts/building-an-ai-chatbot-with-the-openai-api/" rel="noopener noreferrer"&gt;building an OpenAI API chatbot&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Cloudflare Workers AI provides serverless access to open-source models without GPU maintenance.&lt;/li&gt;
&lt;li&gt;Configure access by adding the &lt;code&gt;[ai]&lt;/code&gt; binding block to your &lt;code&gt;wrangler.toml&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Write fetch handlers to execute text generation, translation, or image tasks directly at the edge.&lt;/li&gt;
&lt;li&gt;Enable token streaming with &lt;code&gt;stream: true&lt;/code&gt; to optimise mobile and chat experiences.&lt;/li&gt;
&lt;li&gt;Implement rate limits and prompt sanitisation to protect your edge endpoints in production.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Build Your AI Applications on the Edge
&lt;/h2&gt;

&lt;p&gt;Building reliable AI integrations requires expert knowledge of serverless architecture. Mecanik specialises in &lt;a href="https://mecanik.dev/en/ai-integration-services/" rel="noopener noreferrer"&gt;AI integration services&lt;/a&gt; and custom API setups through our &lt;a href="https://mecanik.dev/en/openai-api-integration/" rel="noopener noreferrer"&gt;OpenAI API integration service&lt;/a&gt;. We build edge-native tools that scale seamlessly, optimising costs and user experiences. Contact us today to discuss your project requirements.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Related reading:&lt;/strong&gt; &lt;a href="https://mecanik.dev/en/posts/reduce-llm-latency-prompt-caching/" rel="noopener noreferrer"&gt;How to Reduce LLM Latency: Caching and Edge Strategies&lt;/a&gt;, &lt;a href="https://mecanik.dev/en/posts/cloudflare-workers-ai-agent/" rel="noopener noreferrer"&gt;Building AI Agents with Cloudflare Workers and LangChain&lt;/a&gt;, &lt;a href="https://mecanik.dev/en/posts/claude-fable-5-hybrid-reasoning-api/" rel="noopener noreferrer"&gt;Claude Fable 5 Hybrid Reasoning: Thinking vs. Speed Modes&lt;/a&gt; and &lt;a href="https://mecanik.dev/en/posts/openai-realtime-api-voice-agent/" rel="noopener noreferrer"&gt;Build Voice Agents: OpenAI Realtime API Guide&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Frequently Asked Questions (FAQ)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What is Cloudflare Workers AI?&lt;/strong&gt;&lt;br&gt;
It is a serverless platform that allows you to run machine learning models (text generation, translation, speech-to-text, image generation) on Cloudflare's global GPU network.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do I need an API key to use Workers AI?&lt;/strong&gt;&lt;br&gt;
No. Once you declare the AI binding in your &lt;code&gt;wrangler.toml&lt;/code&gt; file, Cloudflare handles credentials internally, making the service accessible via &lt;code&gt;env.AI&lt;/code&gt; as shown in this cloudflare workers ai tutorial.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What models are available on Cloudflare Workers AI?&lt;/strong&gt;&lt;br&gt;
The platform hosts popular open-source models, including Meta Llama, Mistral, OpenAI Whisper, and Stable Diffusion, which are updated regularly in their model catalogue.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I stream text responses from Workers AI?&lt;/strong&gt;&lt;br&gt;
Yes. By setting &lt;code&gt;stream: true&lt;/code&gt; in the parameters of your &lt;code&gt;env.AI.run&lt;/code&gt; call, the worker returns a standard &lt;code&gt;ReadableStream&lt;/code&gt; to stream text to the browser.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How does billing work for Workers AI?&lt;/strong&gt;&lt;br&gt;
Billing is based on the number of tokens processed (for text models) or the duration of compute time (for other models), offering a cost-effective utility model.&lt;/p&gt;

</description>
      <category>serverless</category>
      <category>ai</category>
    </item>
    <item>
      <title>Drupal Migration in 2026: Costs, Options and Deadlines</title>
      <dc:creator>Mecanik1337</dc:creator>
      <pubDate>Sun, 04 Oct 2026 18:00:00 +0000</pubDate>
      <link>https://dev.to/mecanik-dev/drupal-migration-in-2026-costs-options-and-deadlines-1h7o</link>
      <guid>https://dev.to/mecanik-dev/drupal-migration-in-2026-costs-options-and-deadlines-1h7o</guid>
      <description>&lt;p&gt;Drupal migration is one of those projects that stays comfortably in next quarter's plan until a date makes it urgent. Two dates are doing that right now, and only one of them is in the future.&lt;/p&gt;

&lt;p&gt;Drupal 7 lost official support on 5 January 2025. Any site still running it has been going without security coverage for well over a year. Drupal 10 reaches end of life on 9 December 2026, the same week Drupal 12 is released, after which it receives no further releases of any kind. If you are on either version, the question is no longer whether to move but which path to take and what it will cost.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Where you stand:&lt;/strong&gt; From Drupal 10 to Drupal 11 is a genuine upgrade — the same site, updated in place, typically two to six weeks. From Drupal 7 to Drupal 11 is not an upgrade at all; it is a rebuild with a content migration attached, and it typically runs three to six months. Confusing the two is the single most expensive mistake in this space, because Drupal 7 sites get quoted as upgrades and then overrun by a factor of four.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  The Two Very Different Migrations
&lt;/h2&gt;

&lt;p&gt;The word migration covers two jobs that share almost nothing beyond the name.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Drupal 10 to 11 is an upgrade.&lt;/strong&gt; The architecture is the same. Your entities, fields, views and configuration carry across. The work is mostly dependency management: making sure every contributed module has a Drupal 11 compatible release, clearing deprecated API calls out of your custom code, and moving to a supported PHP version. It is methodical rather than difficult, and a well-maintained site can be done in a fortnight.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Drupal 7 to Drupal 11 is a rebuild.&lt;/strong&gt; Drupal 8 rewrote the platform on Symfony components, replacing the module API, the theming layer and the configuration system. Nothing carries over automatically except content, and even that arrives through a purpose-built migration process rather than an upgrade script. Your modules do not exist any more, your theme has to be rewritten in Twig, and your custom code has to be reimplemented against a different architecture.&lt;/p&gt;

&lt;p&gt;That second case is why Drupal 7 sites have lingered so long. The honest framing is that you are not upgrading a site, you are building a new one and bringing the content with you.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Each Drupal Migration Path Costs
&lt;/h2&gt;

&lt;p&gt;Figures below assume UK agency rates and a site of moderate complexity. Complexity here means the number of content types, contributed modules and custom modules, not the number of pages.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Drupal 10 to 11, well-maintained site.&lt;/strong&gt; Two to four weeks, roughly £6,000 to £15,000. This is the happy case: modules are current, custom code is small, and the main work is testing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Drupal 10 to 11, neglected site.&lt;/strong&gt; Four to eight weeks, roughly £15,000 to £35,000. Here the blockers are contributed modules with no Drupal 11 release, custom code written against APIs that have since been removed, and a PHP version that also has to move. Every abandoned module becomes a decision: find a replacement, take over maintenance, or reimplement its behaviour.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Drupal 7 to Drupal 11.&lt;/strong&gt; Three to six months, commonly £40,000 to £120,000 and higher for large or heavily customised sites. That range is wide because it is really a rebuild budget. The content migration itself is often the smaller half; the theme, the custom functionality and the integrations are the larger half.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Drupal 7 to a different platform.&lt;/strong&gt; Sometimes the right answer. If the original reason for choosing Drupal no longer applies — the site has become a straightforward marketing site with a blog — then moving to something simpler can cost less than migrating within Drupal, and reduce running costs afterwards. Our comparison of &lt;a href="https://mecanik.dev/en/posts/wordpress-vs-custom-web-development-what-uk-businesses-need-to-know/" rel="noopener noreferrer"&gt;WordPress and custom web development&lt;/a&gt; covers where that line sits, and the &lt;a href="https://mecanik.dev/en/posts/drupal-web-development-a-2026-guide/" rel="noopener noreferrer"&gt;Drupal web development guide&lt;/a&gt; is honest about when Drupal is not the answer.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Contributed Modules Decide Your Timeline
&lt;/h2&gt;

&lt;p&gt;Almost every Drupal upgrade estimate lives or dies on the contrib audit, and it is the first thing worth doing.&lt;/p&gt;

&lt;p&gt;List every contributed module the site uses, then check each one for a stable release compatible with your target version. What you will find falls into four groups. Some have a compatible release and need nothing. Some have a release candidate or a patch in the issue queue that you can apply through Composer. Some have been abandoned, and you must find a replacement, adopt the module yourself, or replace its function with custom code. And some have been absorbed into Drupal core, which is the pleasant surprise of the exercise.&lt;/p&gt;

&lt;p&gt;That audit converts a vague project into a countable one. Until it is done, any quote is a guess, and a supplier who gives you a fixed price without it is either padding heavily or about to raise change requests.&lt;/p&gt;

&lt;p&gt;The same logic applies to custom modules, with a different tool. Drupal's deprecation tooling will scan custom code and report calls to APIs that have been removed or are due for removal, which turns "we have some custom code" into a specific list of files and line numbers.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Actually Goes Wrong
&lt;/h2&gt;

&lt;p&gt;Certain failure modes recur across almost every Drupal migration.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Configuration drift between environments.&lt;/strong&gt; If changes have been made directly in the production admin interface rather than exported to configuration files, your staging environment is not a faithful copy and your testing is worth less than you think. Discovering this mid-migration is common and it always costs time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Content that was never as structured as everyone believed.&lt;/strong&gt; Drupal 7 sites frequently accumulated content in ways nobody documented: fields repurposed for other things, a taxonomy vocabulary doing the job of a workflow state, HTML pasted into body fields carrying inline styles. A migration surfaces all of it at once, and each case needs a decision from someone who knows what the content is for.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Media and file handling.&lt;/strong&gt; Drupal's media handling changed substantially after Drupal 7. Files, image styles and embedded media rarely map one to one, and sites with large media libraries should budget for this specifically rather than assuming it comes free with the content migration.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;URL and SEO continuity.&lt;/strong&gt; This is the one that damages the business rather than the schedule. If URL aliases change without redirects, you lose the rankings the old site earned. Every migration needs a full URL inventory, a redirect map, and verification after launch. Our guide to &lt;a href="https://mecanik.dev/en/posts/website-migration-without-losing-traffic/" rel="noopener noreferrer"&gt;migrating a website without losing traffic&lt;/a&gt; covers that process in detail, and it applies to platform changes just as much as domain changes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Multilingual content.&lt;/strong&gt; If the site runs in several languages, expect the migration to take substantially longer. Language handling was rebuilt after Drupal 7, and translated content, translated configuration and language-specific URL patterns each need their own attention.&lt;/p&gt;




&lt;h2&gt;
  
  
  How to Sequence the Work
&lt;/h2&gt;

&lt;p&gt;The order matters more than most teams expect, and getting it wrong causes rework.&lt;/p&gt;

&lt;p&gt;Start with the contrib and custom code audit, before any estimating. Then get the site onto a supported PHP version and the latest release of its current major version, because that removes a whole category of noise from the actual upgrade. Only then attempt the major version step.&lt;/p&gt;

&lt;p&gt;Build the new environment alongside the old one rather than upgrading in place. That gives you somewhere to test the content migration repeatedly, which you will need, because migrations are run many times before they are run once for real.&lt;/p&gt;

&lt;p&gt;Treat the content migration as code. Drupal's migration framework lets you define migrations in configuration and re-run them, which means you can reset, adjust the mapping and go again. Teams that hand-fix content in the new site rather than fixing the migration definition end up unable to re-run it, and then a single content change in the old site becomes a manual reconciliation.&lt;/p&gt;

&lt;p&gt;Finally, plan a content freeze near the end, and keep it short. Long freezes cause editors to work around you, which produces exactly the drift you were trying to avoid.&lt;/p&gt;




&lt;h2&gt;
  
  
  Should You Move Off Drupal Entirely?
&lt;/h2&gt;

&lt;p&gt;It is a fair question and it deserves an honest answer rather than a defensive one.&lt;/p&gt;

&lt;p&gt;Stay on Drupal when the reasons you chose it still hold: complex content modelling, granular permissions, multilingual requirements, heavy editorial workflow, or accessibility and public sector obligations. Drupal remains genuinely strong at all of these and the upgrade path from here is now stable, with a predictable two-year major release cycle.&lt;/p&gt;

&lt;p&gt;Consider moving when the site has drifted away from those needs. Plenty of Drupal 7 sites are now, in practice, a marketing site with news and a contact form. Migrating that within Drupal means paying rebuild prices for capability you no longer use.&lt;/p&gt;

&lt;p&gt;The decision should turn on the content model and the editorial workload, not on which platform your developer prefers. If nobody can articulate what Drupal is doing for you that a simpler platform could not, that is informative.&lt;/p&gt;




&lt;h2&gt;
  
  
  Get the Audit Before You Get a Quote
&lt;/h2&gt;

&lt;p&gt;Mecanik handles Drupal upgrades and migrations as part of our &lt;a href="https://mecanik.dev/en/services/website-development/" rel="noopener noreferrer"&gt;website development services&lt;/a&gt;. We start with the contrib and custom code audit, because that is what turns an open-ended project into a fixed scope, and it is worth having even if you then take the work elsewhere.&lt;/p&gt;

&lt;p&gt;For Drupal 10 sites the sensible move is to plan the Drupal 11 step now rather than in November, when everyone else is doing it. For Drupal 7 sites the security position is already the argument. If your constraint is capacity rather than expertise, our guide to &lt;a href="https://mecanik.dev/en/posts/hire-drupal-developer-rates-skills-vetting/" rel="noopener noreferrer"&gt;hiring a Drupal developer&lt;/a&gt; covers what to look for.&lt;/p&gt;

&lt;p&gt;Tell us which version you are on and roughly how many contributed and custom modules the site uses, and we will tell you which of the paths above you are actually facing.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Related reading:&lt;/strong&gt; &lt;a href="https://mecanik.dev/en/posts/legacy-php-modernisation-guide/" rel="noopener noreferrer"&gt;Legacy PHP Modernisation: A 2026 Guide&lt;/a&gt;, &lt;a href="https://mecanik.dev/en/posts/symfony-vs-laravel-2026/" rel="noopener noreferrer"&gt;Symfony vs Laravel in 2026: Which PHP Framework to Choose&lt;/a&gt;, &lt;a href="https://mecanik.dev/en/posts/api-security-protect-public-api/" rel="noopener noreferrer"&gt;API Security: How to Protect a Public API in 2026&lt;/a&gt; and &lt;a href="https://mecanik.dev/en/posts/medical-and-healthcare-website-development-in-the-uk/" rel="noopener noreferrer"&gt;Medical &amp;amp; Healthcare Website Development UK 2026&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;When does Drupal 10 stop being supported?&lt;/strong&gt;&lt;br&gt;
Drupal 10 reaches end of life on 9 December 2026, the same week Drupal 12 is released. After that date it receives no further releases, including security fixes, so any site remaining on it is running unsupported.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How much does a Drupal migration cost?&lt;/strong&gt;&lt;br&gt;
A Drupal 10 to 11 upgrade on a well-maintained site typically costs £6,000 to £15,000, rising to £15,000 to £35,000 where modules and custom code are neglected. Drupal 7 to Drupal 11 is a rebuild with content migration and commonly runs £40,000 to £120,000 or more.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why is Drupal 7 to Drupal 11 so much more expensive?&lt;/strong&gt;&lt;br&gt;
Because it is not an upgrade. Drupal 8 rebuilt the platform on Symfony components, replacing the module API, theming layer and configuration system. Modules must be replaced, themes rewritten in Twig and custom code reimplemented, with content brought across through a purpose-built migration.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How long does a Drupal 10 to 11 upgrade take?&lt;/strong&gt;&lt;br&gt;
Two to four weeks for a site whose contributed modules are current and custom code is small, and four to eight weeks where abandoned modules or removed APIs have to be worked around. A contributed module audit up front is what makes the estimate reliable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I migrate from Drupal to WordPress instead?&lt;/strong&gt;&lt;br&gt;
Sometimes that is the right call, particularly where a Drupal 7 site has become a straightforward marketing site with no complex content modelling, permissions or multilingual needs. Base the decision on your content model and editorial workload rather than on platform preference.&lt;/p&gt;

</description>
      <category>php</category>
      <category>refactoring</category>
      <category>webdev</category>
      <category>architecture</category>
    </item>
    <item>
      <title>COBOL Migration Cost, Timeline and Risk - A UK Guide 2026</title>
      <dc:creator>Mecanik1337</dc:creator>
      <pubDate>Sun, 04 Oct 2026 06:00:00 +0000</pubDate>
      <link>https://dev.to/mecanik-dev/cobol-migration-cost-timeline-and-risk-a-uk-guide-2026-5eon</link>
      <guid>https://dev.to/mecanik-dev/cobol-migration-cost-timeline-and-risk-a-uk-guide-2026-5eon</guid>
      <description>&lt;p&gt;"How much will it cost to move off COBOL?" is the first question every board asks, and the honest answer is that it depends on more than the size of the codebase. This guide breaks down what actually drives the cost of a COBOL migration in the UK, realistic budget and timeline ranges, and the risks that turn a well-planned project into an overrun.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A mid-size UK COBOL migration typically costs £200,000 to £800,000 and takes one to two years; full mainframe decommissions run into the millions and multiple years&lt;/li&gt;
&lt;li&gt;Cost is driven far more by codebase complexity, undocumented business logic, and data access redesign than by raw line count&lt;/li&gt;
&lt;li&gt;The choice of target language and migration approach materially changes the budget&lt;/li&gt;
&lt;li&gt;The most common reason projects overrun is underestimating scope, especially undocumented business rules and the data access layer&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What Actually Drives COBOL Migration Cost
&lt;/h2&gt;

&lt;p&gt;Line count is the headline number, but it is a weak predictor on its own. The real cost drivers are:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Complexity, not just size.&lt;/strong&gt; A 100,000-line system of clean batch programs is cheaper to migrate than a 50,000-line system dense with &lt;code&gt;EXEC CICS&lt;/code&gt;, dynamic &lt;code&gt;CALL&lt;/code&gt;s, and intricate &lt;code&gt;REDEFINES&lt;/code&gt;. Transaction processing systems cost more than batch systems of the same size.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Undocumented business logic.&lt;/strong&gt; COBOL systems often carry 30 to 40 years of business rules embedded in code with no external documentation. Rediscovering and validating those rules is frequently the single largest and least predictable line item.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The data access layer.&lt;/strong&gt; &lt;code&gt;EXEC SQL&lt;/code&gt; against DB2 and VSAM file handling rarely convert automatically. They must be redesigned onto the target platform's data access technology, and this is often the biggest work item after business-logic discovery.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Data format conversion.&lt;/strong&gt; Packed decimal (&lt;code&gt;COMP-3&lt;/code&gt;), EBCDIC encoding, and fixed-width layouts all need explicit mapping and testing with real data.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Target language and approach.&lt;/strong&gt; These shift the budget in predictable ways (covered below).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Testing and cut-over.&lt;/strong&gt; Building a regression test suite that proves output parity, and executing a safe cut-over with rollback, is real, non-trivial effort that inexperienced estimates omit.&lt;/p&gt;

&lt;h2&gt;
  
  
  Indicative Cost and Timeline Ranges (UK)
&lt;/h2&gt;

&lt;p&gt;These ranges cover analysis, migration, testing, and go-live support. They exclude ongoing operational costs, training, and downstream integration work that often surfaces mid-project.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;System Size&lt;/th&gt;
&lt;th&gt;Approach&lt;/th&gt;
&lt;th&gt;Estimated Cost&lt;/th&gt;
&lt;th&gt;Typical Timeline&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Small (&amp;lt; 50,000 lines)&lt;/td&gt;
&lt;td&gt;Parallel rewrite&lt;/td&gt;
&lt;td&gt;£80,000 to £200,000&lt;/td&gt;
&lt;td&gt;3 to 9 months&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Medium (50,000 to 500,000 lines)&lt;/td&gt;
&lt;td&gt;Strangler fig&lt;/td&gt;
&lt;td&gt;£200,000 to £800,000&lt;/td&gt;
&lt;td&gt;12 to 24 months&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Large (500,000+ lines)&lt;/td&gt;
&lt;td&gt;Automated + incremental refactor&lt;/td&gt;
&lt;td&gt;£500,000 to £2,000,000+&lt;/td&gt;
&lt;td&gt;2 to 4 years&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Legacy mainframe decommission&lt;/td&gt;
&lt;td&gt;Full programme&lt;/td&gt;
&lt;td&gt;£1,000,000 to £10,000,000+&lt;/td&gt;
&lt;td&gt;3 to 5 years+&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Treat these as planning ranges, not quotes. A proper estimate requires a code assessment; the spread within each band is driven by the complexity factors above.&lt;/p&gt;

&lt;h2&gt;
  
  
  How the Target Language Affects Cost
&lt;/h2&gt;

&lt;p&gt;The destination language changes both the effort profile and the long-term cost of ownership. In broad terms:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://mecanik.dev/en/posts/cobol-to-python-migration-a-uk-enterprise-guide/" rel="noopener noreferrer"&gt;Python&lt;/a&gt;&lt;/strong&gt; maps naturally to COBOL's procedural style and has the largest developer pool, which tends to lower conversion and long-term maintenance cost.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://mecanik.dev/en/posts/cobol-to-csharp-migration-a-uk-enterprise-guide/" rel="noopener noreferrer"&gt;C#&lt;/a&gt;&lt;/strong&gt; is efficient for organisations already on the .NET and Azure stack, and its native &lt;code&gt;decimal&lt;/code&gt; type reduces the effort of getting financial precision right.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://mecanik.dev/en/posts/cobol-to-java-migration-a-uk-enterprise-guide/" rel="noopener noreferrer"&gt;Java&lt;/a&gt;&lt;/strong&gt; suits JVM-based enterprises; &lt;code&gt;BigDecimal&lt;/code&gt; handles precision correctly but adds some verbosity.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://mecanik.dev/en/posts/cobol-to-go-migration-a-uk-enterprise-guide/" rel="noopener noreferrer"&gt;Go&lt;/a&gt;&lt;/strong&gt; is efficient to build and deploy, but the lack of a native decimal type adds review effort for financial fields.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://mecanik.dev/en/posts/cobol-to-rust-migration-a-uk-enterprise-guide/" rel="noopener noreferrer"&gt;Rust&lt;/a&gt;&lt;/strong&gt; tends toward the upper end of any size band because its ownership model adds up-front design effort.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;a href="https://mecanik.dev/en/cobol-migration/" rel="noopener noreferrer"&gt;COBOL migration overview&lt;/a&gt; compares all six target languages side by side to help you choose.&lt;/p&gt;

&lt;h2&gt;
  
  
  How the Migration Approach Affects Cost
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Automated conversion&lt;/strong&gt; reduces the mechanical translation effort but never produces a finished system; budget for the manual work the tooling flags (embedded SQL, CICS, dynamic calls, decimal precision).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Parallel rewrite&lt;/strong&gt; roughly doubles operational cost during the transition because two systems run at once, but it minimises continuity risk. It suits smaller, mission-critical systems.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Incremental (&lt;a href="https://martinfowler.com/bliki/StranglerFigApplication.html" rel="noopener noreferrer"&gt;strangler fig&lt;/a&gt;)&lt;/strong&gt; spreads cost over time and reduces big-bang risk, at the price of a longer hybrid period. It is the most common approach for large UK enterprise systems.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most real projects blend automated conversion with an incremental rollout.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Risks That Cause Overruns
&lt;/h2&gt;

&lt;p&gt;Migrations overrun for predictable reasons. The big five:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Underestimated business-logic discovery.&lt;/strong&gt; The rules are in the code, not in a document. Budget explicit discovery time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data access redesign.&lt;/strong&gt; DB2 and VSAM access does not port automatically. Treat it as its own workstream.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Inadequate regression testing.&lt;/strong&gt; Without output-parity testing on real data, you cannot prove the migration is correct. Build the test suite before migration starts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Decimal precision errors.&lt;/strong&gt; Financial fields mapped to floating-point types silently corrupt money. Map to the correct decimal type for the target language.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cut-over failure.&lt;/strong&gt; The switch to production is the highest-risk moment. A detailed cut-over plan with rollback and reconciliation is mandatory.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  How to Get an Accurate Estimate
&lt;/h2&gt;

&lt;p&gt;A reliable number comes from a code assessment, not a line count. A good assessment inventories programs and copybooks, identifies &lt;code&gt;EXEC SQL&lt;/code&gt; / &lt;code&gt;EXEC CICS&lt;/code&gt; / dynamic-call hotspots, gauges business-logic density, and maps the data access surface. The &lt;a href="https://mecanik.dev/en/services/cobol-migration/" rel="noopener noreferrer"&gt;Mecanik COBOL migration service&lt;/a&gt; provides UK enterprise assessments and full-service migration; for mainframe estates on IBM z/OS, the &lt;a href="https://mecanik.dev/en/legacy-mainframe-migration/" rel="noopener noreferrer"&gt;legacy mainframe migration service&lt;/a&gt; covers the infrastructure decommission alongside the code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A mid-size UK COBOL migration typically costs £200,000 to £800,000 over one to two years; mainframe decommissions run into the millions.&lt;/li&gt;
&lt;li&gt;Complexity, undocumented business logic, and data access redesign drive cost far more than line count.&lt;/li&gt;
&lt;li&gt;Target language and migration approach both move the budget in predictable ways.&lt;/li&gt;
&lt;li&gt;Overruns come from underestimating discovery, testing, and cut-over; a proper code assessment is the only reliable basis for a quote.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Related reading:&lt;/strong&gt; &lt;a href="https://mecanik.dev/en/posts/cobol-modernisation-services-choosing-a-vendor/" rel="noopener noreferrer"&gt;COBOL Modernisation Services: How to Choose a Vendor&lt;/a&gt;, &lt;a href="https://mecanik.dev/en/posts/mainframe-migration-tools-what-works/" rel="noopener noreferrer"&gt;Mainframe Migration Tools: What Works and What Fails&lt;/a&gt;, &lt;a href="https://mecanik.dev/en/posts/mainframe-modernisation-rewrite-refactor-replatform/" rel="noopener noreferrer"&gt;Mainframe Modernisation: Rewrite, Refactor or Replatform&lt;/a&gt; and &lt;a href="https://mecanik.dev/en/posts/cobol-to-java-migration-a-uk-enterprise-guide/" rel="noopener noreferrer"&gt;COBOL to Java Migration - A UK Enterprise Guide 2026&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Frequently Asked Questions (FAQ)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;How much does a COBOL migration cost in the UK?&lt;/strong&gt;&lt;br&gt;
A small system typically costs £80,000 to £200,000, a mid-size system £200,000 to £800,000, and large systems £500,000 upward. Full mainframe decommission programmes run from £1,000,000 into the tens of millions. Complexity, not line count, sets where you land in the range.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How long does a COBOL migration take?&lt;/strong&gt;&lt;br&gt;
Small, well-documented systems take three to nine months. Mid-size enterprise systems run twelve to twenty-four months. Large mainframe programmes take three to five years or more for full decommission.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why do COBOL migration costs vary so much?&lt;/strong&gt;&lt;br&gt;
Because complexity varies enormously. Undocumented business logic, embedded SQL and CICS, data format conversion, the target language, and the migration approach all move the cost. Two systems of the same line count can differ by an order of magnitude.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does automated conversion reduce the cost?&lt;/strong&gt;&lt;br&gt;
It reduces mechanical translation effort, but no tool produces a finished system. You still budget for the data access layer, decimal-precision decisions, testing, and cut-over that the tooling flags for manual work.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is the biggest cause of COBOL migration overruns?&lt;/strong&gt;&lt;br&gt;
Underestimating scope, especially undocumented business logic and the data access redesign. Building a regression test suite for output parity before migration begins is the single most effective way to control that risk.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>refactoring</category>
      <category>architecture</category>
    </item>
    <item>
      <title>WordPress Hacked: Malware Removal and Recovery Guide</title>
      <dc:creator>Mecanik1337</dc:creator>
      <pubDate>Sat, 03 Oct 2026 18:00:00 +0000</pubDate>
      <link>https://dev.to/mecanik-dev/wordpress-hacked-malware-removal-and-recovery-guide-1je7</link>
      <guid>https://dev.to/mecanik-dev/wordpress-hacked-malware-removal-and-recovery-guide-1je7</guid>
      <description>&lt;p&gt;If your WordPress site was hacked and is now showing pharmaceutical spam, redirecting visitors to somewhere unpleasant, or has been flagged by Google as deceptive, start here rather than with a plugin. The instinct is to install a security scanner and click clean. That removes the visible symptom and leaves the way in, which is why so many sites get reinfected within days and their owners conclude that WordPress is simply insecure.&lt;/p&gt;

&lt;p&gt;It is not. Almost every compromise arrives through an out-of-date plugin, and almost every failed cleanup happens because someone removed the malware without removing the access.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;First hour:&lt;/strong&gt; Take the site offline or into maintenance mode. Change the hosting control panel password, the database password, all administrator passwords and the FTP or SSH credentials. Do not restore a backup yet, and do not delete anything yet. You need the current state to work out how they got in, and a restore destroys that evidence while very likely reinstating the same vulnerability.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  What to Do in the First Hour
&lt;/h2&gt;

&lt;p&gt;Order matters here, and the common mistakes are all impatience.&lt;/p&gt;

&lt;p&gt;Take the site down. A maintenance page or a temporary block at the hosting or CDN level protects visitors and stops the site distributing malware while you work. If the site is serving malicious redirects, every hour it stays up compounds the reputational damage.&lt;/p&gt;

&lt;p&gt;Rotate every credential, not just the WordPress admin password. That means hosting panel, database user, FTP and SSH keys, and any API keys stored in the site's configuration. Attackers routinely create a second administrator account or leave a key behind, so changing one password achieves nothing.&lt;/p&gt;

&lt;p&gt;Preserve the evidence before changing anything. Take a full copy of the files and database as they are now, and download the server access logs covering at least the last thirty days. Those logs are how you find the entry point, and many hosts rotate them within days.&lt;/p&gt;

&lt;p&gt;Then, and only then, work out what happened.&lt;/p&gt;




&lt;h2&gt;
  
  
  How Your WordPress Site Got Hacked: Finding the Entry Point
&lt;/h2&gt;

&lt;p&gt;Cleaning without diagnosis is why reinfection is so common. Four checks find the cause in most cases.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Check plugin and theme versions against known vulnerabilities.&lt;/strong&gt; Out-of-date plugins are far and away the leading cause. Note every plugin, its version, and whether a security release exists that you have not applied. Pay particular attention to anything with an expired licence, because premium plugins stop receiving updates when the licence lapses while continuing to appear installed and active.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Read the access logs around the first sign of trouble.&lt;/strong&gt; You are looking for POST requests to unusual paths, requests to files that should not exist, and a burst of activity from one address shortly before the defacement. This is usually where the answer is.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Look for files that do not belong.&lt;/strong&gt; Recently modified PHP files in the uploads directory are a strong signal, because nothing should ever execute there. So are files with names designed to look plausible, and modifications to &lt;code&gt;wp-config.php&lt;/code&gt; or &lt;code&gt;.htaccess&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Check for added administrator accounts and scheduled tasks.&lt;/strong&gt; Attackers commonly create a user to return through, and register a scheduled task that reinstalls the payload after you clean it. A site that keeps reinfecting on a regular cycle almost always has a scheduled task nobody looked for.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why "Just Restore a Backup" Usually Fails
&lt;/h2&gt;

&lt;p&gt;It is the first suggestion everyone receives and it is right about a third of the time.&lt;/p&gt;

&lt;p&gt;Restoring works when you know the compromise date, have a backup from before it, and have identified and fixed the vulnerability. Without all three it fails predictably. Restore a backup from last week and you may be restoring a site that was already compromised two weeks ago and merely quiet. Restore without patching the vulnerable plugin and you have rebuilt the door you were locked out of.&lt;/p&gt;

&lt;p&gt;There is also the problem of what a restore costs you. On a store or a membership site, rolling back means losing every order, registration and comment since the backup. That is often unacceptable, which pushes you towards cleaning the live site rather than replacing it.&lt;/p&gt;

&lt;p&gt;The reliable approach is a rebuild rather than a restore. Install WordPress core fresh, install clean copies of every plugin and theme from their official sources rather than from the compromised site, and carry across only the uploads directory and the database — both inspected first. That guarantees the executable code is clean, which file-by-file cleaning never quite does.&lt;/p&gt;




&lt;h2&gt;
  
  
  Cleaning the Database
&lt;/h2&gt;

&lt;p&gt;The database is where incomplete cleanups leave things behind, because scanners concentrate on files.&lt;/p&gt;

&lt;p&gt;Injected content usually appears in post content as hidden links or iframes, in the options table where redirect scripts get stored, and in user metadata. Search for script tags, base64-encoded blocks and unfamiliar domains across the content and options tables.&lt;/p&gt;

&lt;p&gt;Check the users table by hand. Look at every account with administrator privileges and confirm you recognise each one, then check registration dates against your own records.&lt;/p&gt;

&lt;p&gt;Look at scheduled tasks, which in WordPress live in the options table. An entry pointing at a function you do not recognise is how a site reinfects itself on schedule long after the files were cleaned.&lt;/p&gt;

&lt;p&gt;Take particular care with anything encoded. Attackers obfuscate payloads specifically so a search for obvious strings misses them, so decode anything suspicious rather than assuming it is a legitimate plugin doing something clever.&lt;/p&gt;




&lt;h2&gt;
  
  
  Getting Unflagged and Recovering Rankings
&lt;/h2&gt;

&lt;p&gt;Cleaning the site is not the end, because the warnings persist until you ask for them to be reviewed.&lt;/p&gt;

&lt;p&gt;If Google has flagged the site, the security issues report in Search Console tells you what was detected and lets you request a review once you have fixed it. Only request the review after the site is genuinely clean, because a failed review lengthens the process.&lt;/p&gt;

&lt;p&gt;Check whether the domain has landed on blocklists used by browsers and email providers. Being clean is not enough on its own; each maintains its own list and its own removal process.&lt;/p&gt;

&lt;p&gt;Then look at the damage. Search visibility usually recovers once warnings are lifted, but a site that spent weeks serving spam pages may have had those pages indexed. Check for indexed URLs that were never yours, remove them, and confirm the clean versions are being crawled. Our &lt;a href="https://mecanik.dev/en/posts/website-security-audit-cost-mitigation-guide/" rel="noopener noreferrer"&gt;website security audit guide&lt;/a&gt; covers the verification steps in more detail.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Professional Recovery Costs
&lt;/h2&gt;

&lt;p&gt;Prices reflect typical UK rates and vary with how long the compromise went unnoticed.&lt;/p&gt;

&lt;p&gt;A straightforward cleanup on a small site caught quickly, with a known cause, generally runs £400 to £1,200 and takes a day or two. This is the common case when someone notices within a week.&lt;/p&gt;

&lt;p&gt;A full incident response — log analysis to establish entry point and timeline, clean rebuild, database inspection, credential rotation, hardening and blocklist removal — typically runs £1,500 to £5,000. This is what a store or a site holding customer data should expect, because you also need to establish whether data was accessed.&lt;/p&gt;

&lt;p&gt;Sites compromised for months, or hosting several sites on the same account, cost more, because cross-contamination between sites on shared hosting is common and each one must be checked.&lt;/p&gt;

&lt;p&gt;If personal data may have been accessed, there are obligations beyond the technical cleanup. UK GDPR requires notifying the ICO within 72 hours of becoming aware of a qualifying breach, and that clock starts at awareness, not at cleanup. Take advice early rather than after you have finished tidying. Our guide to &lt;a href="https://mecanik.dev/en/posts/gdpr-technical-compliance-for-uk-developers-in-2026/" rel="noopener noreferrer"&gt;GDPR technical compliance&lt;/a&gt; covers the engineering side of that.&lt;/p&gt;




&lt;h2&gt;
  
  
  Making Sure It Does Not Happen Again
&lt;/h2&gt;

&lt;p&gt;Recovery without hardening just resets the clock.&lt;/p&gt;

&lt;p&gt;Update discipline is the whole game. The overwhelming majority of compromises exploit a vulnerability with a patch already available, so the fix is a routine that applies security releases promptly and a policy of removing anything unmaintained. Premium plugins with lapsed licences should be renewed or replaced, never left in place.&lt;/p&gt;

&lt;p&gt;Reduce what can execute. Nothing in the uploads directory should ever run as PHP, file editing from the admin interface should be disabled, and administrator accounts should be few and individually named.&lt;/p&gt;

&lt;p&gt;Add multi-factor authentication on every administrator account and rate-limit the login endpoint. Most credential attacks are automated and stop being viable the moment a second factor exists.&lt;/p&gt;

&lt;p&gt;Finally, back up properly and test it. A backup you have never restored is a hypothesis. Keep several generations, because the newest one may already contain the compromise. Our &lt;a href="https://mecanik.dev/en/posts/wordpress-security-hardening-checklist-2026/" rel="noopener noreferrer"&gt;WordPress security hardening checklist&lt;/a&gt; sets out the full configuration, and our &lt;a href="https://mecanik.dev/en/posts/wordpress-performance-audit-core-web-vitals/" rel="noopener noreferrer"&gt;WordPress performance audit guide&lt;/a&gt; covers the plugin discipline that reduces the attack surface as a side effect.&lt;/p&gt;




&lt;h2&gt;
  
  
  Get It Cleaned Properly
&lt;/h2&gt;

&lt;p&gt;Mecanik provides &lt;a href="https://mecanik.dev/en/wordpress-security-audit/" rel="noopener noreferrer"&gt;WordPress security audit&lt;/a&gt; and incident recovery work: establishing how the compromise happened, rebuilding cleanly rather than patching over it, inspecting the database, and hardening the site so the same route closes behind you.&lt;/p&gt;

&lt;p&gt;We work from the server logs rather than from a scanner's output, because a scanner tells you what it recognises and the logs tell you what actually happened. Where the site handles customer data we will also tell you plainly whether you appear to have a notifiable breach, rather than leaving you to discover that later. Ongoing maintenance is available through our &lt;a href="https://mecanik.dev/en/wordpress-developer-for-hire/" rel="noopener noreferrer"&gt;WordPress development service&lt;/a&gt;, which is generally cheaper than a second incident.&lt;/p&gt;

&lt;p&gt;If your site is compromised right now, take it offline, rotate the credentials, keep the logs, and get in touch.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Related reading:&lt;/strong&gt; &lt;a href="https://mecanik.dev/en/posts/api-security-protect-public-api/" rel="noopener noreferrer"&gt;API Security: How to Protect a Public API in 2026&lt;/a&gt;, &lt;a href="https://mecanik.dev/en/posts/owasp-top-10-explained-for-business-owners/" rel="noopener noreferrer"&gt;OWASP Top 10 Explained for Business Owners&lt;/a&gt;, &lt;a href="https://mecanik.dev/en/posts/server-security-audit-what-gets-checked/" rel="noopener noreferrer"&gt;Server Security Audit Checklist: What Actually Gets Checked&lt;/a&gt; and &lt;a href="https://mecanik.dev/en/posts/website-security-audit-for-uk-businesses-in-2026/" rel="noopener noreferrer"&gt;Website Security Audit Guide for UK Businesses in 2026&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What should I do first if my WordPress site is hacked?&lt;/strong&gt;&lt;br&gt;
Take the site offline, rotate every credential including hosting, database, FTP and all administrator accounts, and preserve a copy of the current files, database and server logs. Do not restore a backup or delete files yet, because that destroys the evidence needed to find the entry point.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why does my WordPress site keep getting reinfected?&lt;/strong&gt;&lt;br&gt;
Almost always because the cleanup removed the malware but not the access. Look for administrator accounts you do not recognise, backdoors in the uploads directory, and scheduled tasks in the options table that reinstall the payload. Reinfection on a regular cycle usually indicates a scheduled task.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I just restore a backup to fix a hacked site?&lt;/strong&gt;&lt;br&gt;
Only if you know when the compromise happened, have a backup from before it, and have fixed the underlying vulnerability. Without all three you risk restoring an already-compromised site or reopening the same hole. A clean rebuild with fresh core, plugins and themes is more reliable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How much does WordPress malware removal cost?&lt;/strong&gt;&lt;br&gt;
A straightforward cleanup on a small site caught early typically costs £400 to £1,200. A full incident response with log analysis, clean rebuild, database inspection and hardening generally runs £1,500 to £5,000, and long-running or multi-site compromises cost more.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do I get my site unflagged by Google?&lt;/strong&gt;&lt;br&gt;
Clean the site fully, then request a review through the security issues report in Search Console. Only request it once the site is genuinely clean, since a failed review lengthens the process, and check separately for browser and email blocklists which each have their own removal procedure.&lt;/p&gt;

</description>
      <category>wordpress</category>
      <category>security</category>
      <category>cybersecurity</category>
    </item>
    <item>
      <title>WooCommerce Performance: Why Your Store Is Slow</title>
      <dc:creator>Mecanik1337</dc:creator>
      <pubDate>Sat, 03 Oct 2026 06:00:00 +0000</pubDate>
      <link>https://dev.to/mecanik-dev/woocommerce-performance-why-your-store-is-slow-38c</link>
      <guid>https://dev.to/mecanik-dev/woocommerce-performance-why-your-store-is-slow-38c</guid>
      <description>&lt;p&gt;Almost every WooCommerce performance investigation starts the same way. The store owner has already moved to a faster host, installed a caching plugin, and bought an image optimiser, and the site is still slow. They conclude that WooCommerce is simply heavy and give up.&lt;/p&gt;

&lt;p&gt;WooCommerce is heavier than a brochure site, which is unavoidable when every page can carry a cart. But a store that takes six seconds to load is not suffering from that overhead. It is suffering from something specific, and in my experience it is nearly always one of four things.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The short version:&lt;/strong&gt; Shops are slow because cart and checkout pages cannot be page-cached, because the options table has grown enormous with autoloaded junk, because product queries scan an unindexed metadata table, and because thirty plugins each add their own scripts to every page. Hosting is the last thing to change, not the first.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Why a Store Is Different From a Blog
&lt;/h2&gt;

&lt;p&gt;Understanding one distinction explains most WooCommerce performance behaviour.&lt;/p&gt;

&lt;p&gt;A blog post is the same for every visitor, so it can be generated once and served from cache to everyone. That is why brochure sites are fast almost regardless of how they are built. A store cannot do that on every page, because the cart is personal. The moment a visitor adds an item, the page has to reflect their state rather than a shared copy.&lt;/p&gt;

&lt;p&gt;The consequence is that cart, checkout and account pages bypass page caching entirely and execute PHP and database queries on every request. Those are also the pages where slowness costs you money directly. A slow category page loses browsers; a slow checkout loses buyers.&lt;/p&gt;

&lt;p&gt;So the useful question is never "is my site fast?" It is "how fast is my site for a logged-in visitor with something in their cart?" Test that state specifically, because it is the one your revenue depends on and the one every synthetic speed test misses.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Four Things That Are Actually Wrong
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;An overloaded options table.&lt;/strong&gt; WordPress loads a set of options on every single request, and plugins add to it freely. Uninstalled plugins routinely leave their rows behind. On older stores this table grows to tens of megabytes of autoloaded data being read on every page view including the checkout. It is invisible, it is cumulative, and it is one of the highest-return fixes available. Check the total size of autoloaded options first; if it is measured in megabytes rather than kilobytes, you have found real time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Product queries against unindexed metadata.&lt;/strong&gt; WooCommerce historically stored product attributes, prices and stock in a generic metadata table shared with everything else. Filtering or sorting a large catalogue means joining that table repeatedly. With a few hundred products nobody notices. With tens of thousands, category and filter pages slow to a crawl. Newer WooCommerce versions moved order data to dedicated tables specifically to relieve this pressure, and enabling that storage on a store with a long order history is usually worth doing on its own.&lt;/p&gt;

&lt;h3&gt;
  
  
  Plugins and External Calls
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Plugin sprawl on the critical path.&lt;/strong&gt; The problem is rarely the count itself; it is that most plugins enqueue their CSS and JavaScript on every page rather than only where needed. A booking plugin used on one page loads its assets on your checkout. The fix is unglamorous: audit what each plugin loads, dequeue assets outside their own pages, and remove anything whose function you cannot name.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Uncached third-party calls.&lt;/strong&gt; Live shipping rates, tax lookups, currency conversion and stock checks against an external system all place a network request inside the page load. When that provider is slow, your checkout is slow, and when it fails your checkout fails. Every external call in a request path needs a timeout, a cache and a fallback. Our guide to &lt;a href="https://mecanik.dev/en/posts/third-party-api-integration-cost-failure-modes/" rel="noopener noreferrer"&gt;third-party API integration&lt;/a&gt; covers how that should be built.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Actually Helps, In Order
&lt;/h2&gt;

&lt;p&gt;Work through these in sequence, because each one changes what the next measurement tells you.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Object caching, not just page caching.&lt;/strong&gt; Page caching serves whole HTML pages and cannot help cart or checkout. A persistent object cache stores the results of database queries in memory and speeds up exactly the pages page caching cannot touch. For a store this is usually the single largest improvement available, and it is the step most often skipped because the caching plugin already installed gave the impression the job was done.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Database maintenance.&lt;/strong&gt; Clear expired transients, remove orphaned metadata from deleted products and orders, and trim post revisions. On a store that has been trading for years this routinely removes a large fraction of the database. Schedule it rather than doing it once.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Then hosting.&lt;/strong&gt; Once caching and the database are in order, hosting genuinely matters: PHP version, available memory, whether the database is on the same machine, and whether you are on shared hosting competing with other tenants. But moving host before fixing the above just relocates the problem to a more expensive address.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Assets last.&lt;/strong&gt; Image formats, lazy loading and script deferral are worth doing and they are what most guides lead with. They improve the loading experience of pages that were already being served reasonably quickly. They do very little for a checkout that spends four seconds in PHP before sending a byte.&lt;/p&gt;




&lt;h2&gt;
  
  
  Measuring WooCommerce Performance Properly
&lt;/h2&gt;

&lt;p&gt;Synthetic scores mislead store owners more than any other group, so measure deliberately.&lt;/p&gt;

&lt;p&gt;Test the logged-in, cart-populated state. Most tools test an anonymous visitor hitting the homepage, which is the fastest possible path through your site and tells you almost nothing about checkout.&lt;/p&gt;

&lt;p&gt;Separate server time from front-end time. If the server takes three seconds to produce the HTML, no amount of image optimisation will save the page. Time to first byte tells you which half of the problem you have, and therefore which of the fixes above applies.&lt;/p&gt;

&lt;p&gt;Use field data rather than lab data where you can. Real visitors on real connections and real phones produce a different picture from a test run in a data centre, and Core Web Vitals are assessed on the former. Our &lt;a href="https://mecanik.dev/en/posts/wordpress-performance-audit-core-web-vitals/" rel="noopener noreferrer"&gt;WordPress performance audit guide&lt;/a&gt; covers how to read those metrics properly, and &lt;a href="https://mecanik.dev/en/posts/core-web-vitals-2026-how-to-pass/" rel="noopener noreferrer"&gt;Core Web Vitals in 2026&lt;/a&gt; explains what the thresholds actually require.&lt;/p&gt;

&lt;p&gt;Finally, watch the database directly during a slow request. A query log showing the same query executed two hundred times on one page load identifies the culprit immediately, and that pattern is extremely common in stores running several plugins that each ask for product data independently.&lt;/p&gt;




&lt;h2&gt;
  
  
  What This Work Costs
&lt;/h2&gt;

&lt;p&gt;Prices below reflect typical UK agency rates for a store of moderate size.&lt;/p&gt;

&lt;p&gt;A performance audit that identifies the specific causes, with a prioritised fix list and before-and-after measurements, generally runs £900 to £2,500. That is a diagnostic engagement and it is worth buying separately, because it tells you whether the remaining work is a week or a month.&lt;/p&gt;

&lt;p&gt;Implementing the common fixes — object caching, database cleanup, plugin asset auditing, external call caching — usually runs £2,000 to £6,000 depending on how much has accumulated.&lt;/p&gt;

&lt;p&gt;Deeper work costs more because it is genuinely development. Migrating a large catalogue to indexed storage, rebuilding a filter system that scans metadata, or replacing a slow plugin with a targeted custom implementation typically falls between £6,000 and £20,000.&lt;/p&gt;

&lt;p&gt;The figure that matters more than any of these is what slowness costs you. Checkout abandonment rises measurably with load time, so a store turning over meaningful revenue can usually justify the audit on the checkout page alone.&lt;/p&gt;




&lt;h2&gt;
  
  
  Fix the Store, Not the Score
&lt;/h2&gt;

&lt;p&gt;Mecanik does WooCommerce performance work as part of our &lt;a href="https://mecanik.dev/en/wordpress-developer-for-hire/" rel="noopener noreferrer"&gt;WordPress development service&lt;/a&gt;, and we start by measuring the logged-in checkout path rather than the homepage, because that is where stores actually lose money.&lt;/p&gt;

&lt;p&gt;We look at autoloaded options, order storage, query patterns and external calls before recommending a host change, and we give you the measurements both before and after so the improvement is verifiable rather than asserted. If your store is slow because it has outgrown the platform rather than because it is misconfigured, we will tell you that too — our comparison of &lt;a href="https://mecanik.dev/en/posts/ecommerce-website-development-shopify-vs-custom-in-2026/" rel="noopener noreferrer"&gt;Shopify and custom ecommerce&lt;/a&gt; covers where that line sits.&lt;/p&gt;

&lt;p&gt;Send us the URL and roughly how many products and orders the store holds, and we will tell you which of the four causes above you are most likely facing.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Related reading:&lt;/strong&gt; &lt;a href="https://mecanik.dev/en/posts/wordpress-hacked-malware-removal-recovery/" rel="noopener noreferrer"&gt;WordPress Hacked: Malware Removal and Recovery Guide&lt;/a&gt;, &lt;a href="https://mecanik.dev/en/posts/scale-ecommerce-business-uk-tech-playbook/" rel="noopener noreferrer"&gt;How to Scale an E-commerce Business in the UK: 2026 Guide&lt;/a&gt;, &lt;a href="https://mecanik.dev/en/posts/hire-drupal-developer-rates-skills-vetting/" rel="noopener noreferrer"&gt;Hire a Drupal Developer: Rates, Skills and Vetting&lt;/a&gt; and &lt;a href="https://mecanik.dev/en/posts/how-much-does-a-website-cost-in-the-uk-in-2026/" rel="noopener noreferrer"&gt;How Much Does a Website Cost in the UK in 2026?&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Why is my WooCommerce site slow even with a caching plugin?&lt;/strong&gt;&lt;br&gt;
Page caching cannot be applied to cart, checkout and account pages, because those must reflect each visitor's own state. Those pages execute PHP and database queries on every request, so speeding them up requires object caching and database work rather than page caching.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does moving to better hosting fix WooCommerce performance?&lt;/strong&gt;&lt;br&gt;
Only partly, and it should not be the first step. If the options table is bloated, queries are unindexed and plugins load assets everywhere, better hosting makes the same problems slightly faster at higher cost. Fix caching and the database first, then reassess hosting.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How many plugins are too many for WooCommerce?&lt;/strong&gt;&lt;br&gt;
The count matters less than what each one loads. Twenty well-behaved plugins that only enqueue assets on their own pages cause less harm than eight that load scripts site-wide. Audit what each adds to the checkout, and remove anything whose purpose nobody can state.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What does WooCommerce speed optimisation cost?&lt;/strong&gt;&lt;br&gt;
A diagnostic audit with a prioritised fix list typically costs £900 to £2,500. Implementing common fixes such as object caching, database cleanup and asset auditing usually runs £2,000 to £6,000, while catalogue or filter rework can reach £6,000 to £20,000.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How should I test WooCommerce performance properly?&lt;/strong&gt;&lt;br&gt;
Test as a logged-in visitor with items in the cart, not an anonymous homepage visit. Separate server response time from front-end rendering to see which half is slow, and use field data from real visitors rather than relying only on lab scores.&lt;/p&gt;

</description>
      <category>wordpress</category>
      <category>ecommerce</category>
      <category>performance</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Penetration Testing Cost: 2026 Enterprise Budgeting Guide</title>
      <dc:creator>Mecanik1337</dc:creator>
      <pubDate>Fri, 02 Oct 2026 18:00:00 +0000</pubDate>
      <link>https://dev.to/mecanik-dev/penetration-testing-cost-2026-enterprise-budgeting-guide-44ih</link>
      <guid>https://dev.to/mecanik-dev/penetration-testing-cost-2026-enterprise-budgeting-guide-44ih</guid>
      <description>&lt;p&gt;Calculating the cost of penetration testing in the UK is a vital compliance task for enterprises planning cyber security audits in 2026. With business transactions shifting online, maintaining strict application security is critical to protect sensitive client databases and avoid expensive regulatory penalties. Commissioning an annual penetration test has shifted from a general recommendation to a standard requirement under local frameworks. This guide breaks down the pricing models, scope definitions, and compliance standards used to calculate penetration testing budgets.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Compliance Risk Warning:&lt;/strong&gt; Relying purely on automated vulnerability scanners does not constitute a penetration test. Under standard industry frameworks, automated tools fail to identify complex logic bugs, leaving your systems vulnerable to manual breaches.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key Takeaways:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Costs vary based on IP count, active user roles, and network complexity.&lt;/li&gt;
&lt;li&gt;Small-scale web application pen tests range from £3,500 to £6,500, while complex enterprise networks start at £8,000.&lt;/li&gt;
&lt;li&gt;Working with CREST-accredited agencies is essential to pass compliance frameworks like ISO 27001 or PCI-DSS.&lt;/li&gt;
&lt;li&gt;Retaining a detailed vulnerability report simplifies structural remediation, saving engineering hours post-audit.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Variables That Dictate Penetration Testing Cost
&lt;/h2&gt;

&lt;p&gt;A professional security audit requires manual validation by experienced ethical hackers. According to guidelines from the &lt;a href="https://www.ncsc.gov.uk/" rel="noopener noreferrer"&gt;National Cyber Security Centre (NCSC)&lt;/a&gt;, scoping security tests accurately is the first step to prevent budget overruns. Several parameters directly impact the scope of work and the final quote. Therefore, you must define the target surfaces cleanly to avoid budget creep.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Scope and Target Count
&lt;/h3&gt;

&lt;p&gt;The number of servers, external IP addresses, internal domains, and active APIs dictates the test duration. Additionally, a web application with multiple user access levels requires testing each authorisation path to identify privilege escalation risks.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Testing Methodology: Black vs. White Box
&lt;/h3&gt;

&lt;p&gt;The amount of information provided to the security engineers determines the testing path and, ultimately, the testing style.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Black-Box Testing:&lt;/strong&gt; Engineers receive only the target URL or IP. This method simulates an external attack, requiring more hours to gather intelligence and map endpoints.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;White-Box Testing:&lt;/strong&gt; Developers provide source code access, network diagrams, and database configurations. This allows for deep review but requires close collaboration.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Compliance and Industry Requirements
&lt;/h3&gt;

&lt;p&gt;UK businesses bidding for public sector contracts or working in fintech must meet specific security baselines (such as Cyber Essentials Plus or PCI-DSS). To satisfy these audit criteria, the testing agency must run specialised tests, and this additional compliance layer increases testing hours and the final fee.&lt;/p&gt;




&lt;h2&gt;
  
  
  Average Penetration Testing Costs in the UK for 2026
&lt;/h2&gt;

&lt;p&gt;To help your compliance team budget, the following table details the average cost metrics for security audits in the UK:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Testing Target&lt;/th&gt;
&lt;th&gt;Average Cost Range (GBP)&lt;/th&gt;
&lt;th&gt;Recommended Testing Frequency&lt;/th&gt;
&lt;th&gt;Compliance Standards Met&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Simple Web App / API&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;£3,500 - £6,500&lt;/td&gt;
&lt;td&gt;Annual / Post-Update&lt;/td&gt;
&lt;td&gt;GDPR / OWASP Top 10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Enterprise Network (Internal &amp;amp; External)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;£8,000 - £15,000+&lt;/td&gt;
&lt;td&gt;Annual&lt;/td&gt;
&lt;td&gt;ISO 27001 / PCI-DSS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Active Mobile Application (iOS &amp;amp; Android)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;£5,000 - £10,000&lt;/td&gt;
&lt;td&gt;Annual&lt;/td&gt;
&lt;td&gt;OWASP MASVS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cloud Infrastructure (AWS/Cloudflare)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;£6,000 - £12,000&lt;/td&gt;
&lt;td&gt;Annual / Major Change&lt;/td&gt;
&lt;td&gt;CIS Benchmarks&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;These estimates assume hiring a certified agency that provides comprehensive liability insurance and senior, accredited testers.&lt;/p&gt;




&lt;h2&gt;
  
  
  How a Pen-Test Quote Is Built: A Worked Example
&lt;/h2&gt;

&lt;p&gt;Most reputable UK consultancies price on a &lt;strong&gt;day-rate basis&lt;/strong&gt;. The quote is simply the estimated number of testing days multiplied by the consultant day rate, plus reporting and a retest. This makes the arithmetic easy to interrogate once you know the inputs. For CREST-registered testers, day rates typically sit between &lt;strong&gt;£1,000 and £1,500 per day&lt;/strong&gt; (illustrative for 2026); highly specialised work — bespoke thick-client, embedded, or hardware testing — commands more.&lt;/p&gt;

&lt;p&gt;Consider a realistic scenario: a mid-sized SaaS business commissioning its annual assessment. The in-scope assets are a customer-facing web application with three user roles, the REST API behind it, and a small external network perimeter. A blended senior rate of &lt;strong&gt;£1,200 per day&lt;/strong&gt; applies across the engagement.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Component&lt;/th&gt;
&lt;th&gt;Scope detail&lt;/th&gt;
&lt;th&gt;Estimated effort (days)&lt;/th&gt;
&lt;th&gt;Subtotal at £1,200/day&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Web application (authenticated)&lt;/td&gt;
&lt;td&gt;3 user roles, ~25 dynamic pages&lt;/td&gt;
&lt;td&gt;5.0&lt;/td&gt;
&lt;td&gt;£6,000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;REST API&lt;/td&gt;
&lt;td&gt;~40 endpoints&lt;/td&gt;
&lt;td&gt;2.5&lt;/td&gt;
&lt;td&gt;£3,000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;External network&lt;/td&gt;
&lt;td&gt;12 live IP addresses&lt;/td&gt;
&lt;td&gt;1.5&lt;/td&gt;
&lt;td&gt;£1,800&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reporting &amp;amp; QA&lt;/td&gt;
&lt;td&gt;Findings write-up, executive summary, peer review&lt;/td&gt;
&lt;td&gt;1.5&lt;/td&gt;
&lt;td&gt;£1,800&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Remediation retest&lt;/td&gt;
&lt;td&gt;Verify critical and high-severity fixes&lt;/td&gt;
&lt;td&gt;1.0&lt;/td&gt;
&lt;td&gt;£1,200&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Total&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;11.5 days&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;£13,800&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The headline figure of roughly &lt;strong&gt;£13,800&lt;/strong&gt; is therefore not a mysterious lump sum. It is 11.5 days of effort at a £1,200 blended rate. The day counts themselves come from a scoping questionnaire: the tester estimates hours per authorisation path, per endpoint cluster, and per network segment, then rounds to sensible half-days. Change any input and the price moves predictably. Add a native mobile application and you add roughly 4 to 6 days (£4,800–£7,200). Insist on a fully black-box engagement and reconnaissance alone can add a day or two, because the team must map from scratch what a white-box brief would have handed over.&lt;/p&gt;

&lt;p&gt;Most agencies present this as a &lt;strong&gt;fixed-price quote&lt;/strong&gt; rather than an open day rate, having converted their day estimate into a single figure. The practical difference matters at contract time: a fixed price protects you if the work runs long, but only against the scope you agreed, so anything discovered outside the original boundary becomes a change request. Always confirm what the quote assumes — the number of days baked in, whether one retest is included, and how out-of-scope findings are handled — before you sign. A supplier who cannot break their fixed price back down into days and rates is a supplier worth questioning.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Makes Up the Headline Price: A Line-Item Breakdown
&lt;/h2&gt;

&lt;p&gt;Even within a single engagement, the fee covers far more than hands-on-keyboard exploitation. Understanding how the effort divides helps you compare quotes like for like and spot a supplier who has under-scoped the unglamorous stages.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Stage&lt;/th&gt;
&lt;th&gt;What it covers&lt;/th&gt;
&lt;th&gt;Typical share of effort&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Scoping &amp;amp; pre-engagement&lt;/td&gt;
&lt;td&gt;Questionnaire, rules of engagement, written authorisation&lt;/td&gt;
&lt;td&gt;5–10%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reconnaissance &amp;amp; mapping&lt;/td&gt;
&lt;td&gt;Enumerating the attack surface, cataloguing endpoints&lt;/td&gt;
&lt;td&gt;10–15%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Active testing &amp;amp; exploitation&lt;/td&gt;
&lt;td&gt;Manual testing, chaining findings, privilege escalation&lt;/td&gt;
&lt;td&gt;45–55%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reporting &amp;amp; QA review&lt;/td&gt;
&lt;td&gt;Write-up, severity ratings, senior peer review&lt;/td&gt;
&lt;td&gt;20–25%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Remediation retest&lt;/td&gt;
&lt;td&gt;Re-testing issues your team has patched&lt;/td&gt;
&lt;td&gt;5–10%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The reporting stage surprises many first-time buyers. A test that finds serious problems but documents them poorly is close to worthless: your engineers cannot reproduce or prioritise what they cannot understand. When you analyse two quotes and one is conspicuously cheaper, check whether it has quietly compressed reporting and retesting — that is usually where corners get cut.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ongoing and Hidden Costs to Budget For
&lt;/h2&gt;

&lt;p&gt;The invoice from the testing agency is rarely the whole story. A realistic annual security budget should account for these recurring or easily overlooked items:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Remediation engineering time.&lt;/strong&gt; Fixing what the test finds is frequently the single largest cost, and it lands on your own team rather than the supplier's invoice. A report with a dozen medium and high findings can absorb several developer-weeks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Annual re-testing.&lt;/strong&gt; Frameworks such as ISO 27001 and PCI-DSS expect a fresh assessment at least yearly, plus targeted testing after any major change.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Retest and validation fees.&lt;/strong&gt; Most engagements include one retest window; verifying fixes after that window has closed is usually billed separately.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Interim scanning and tooling.&lt;/strong&gt; Many organisations run authenticated vulnerability scanning between annual tests, which carries its own licence cost.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Internal staff time.&lt;/strong&gt; Scoping calls, environment preparation, and provisioning test accounts all consume hours that rarely appear in any quote.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As an annual rule of thumb, plan for total security-testing spend of roughly &lt;strong&gt;1.5 to 2 times the headline test fee&lt;/strong&gt; once remediation labour, retests, and interim scanning are included (illustrative). In our worked example, the £13,800 engagement realistically implies a &lt;strong&gt;£20,000–£28,000&lt;/strong&gt; all-in annual figure for that programme of work.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Moves the Price Up or Down
&lt;/h2&gt;

&lt;p&gt;Because the model is days multiplied by a rate, every price lever ultimately changes the day count. The factors below push a quote in one direction or the other:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pushes it up:&lt;/strong&gt; a fully black-box brief, many user roles or authorisation boundaries, compliance overlays such as PCI-DSS or CBEST that mandate specific methodologies and evidence, out-of-hours testing to protect production, and any physical or social-engineering component.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pulls it down:&lt;/strong&gt; a tightly defined and well-documented scope, white-box or grey-box access, consolidating several assets into one booking, a stable code freeze during the test window, and a standing retainer relationship that removes repeated scoping overhead.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Best Practices to Control Testing Expenses
&lt;/h2&gt;

&lt;p&gt;Protecting your budget from inflation requires preparing your systems before the audit begins. To keep costs under control, follow these optimisation guidelines:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Clean up Active Codebases:&lt;/strong&gt; Resolve obvious OWASP vulnerability points using automated scanners before the engineers start testing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Establish Clear Scopes:&lt;/strong&gt; Exclude non-critical staging subdomains or legacy static servers from the target list to limit testing hours.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Verify Third-Party Approvals:&lt;/strong&gt; If your systems are hosted on managed servers, ensure you secure authorisation from the host to prevent testing blocks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Link remediations to SLAs:&lt;/strong&gt; Ensure your engineering team is scheduled to patch identified vulnerabilities immediately upon receiving the draft report.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Partner with a Vetted UK Security Consultancy
&lt;/h2&gt;

&lt;p&gt;Understanding the elements that shape your budget ensures your compliance audits stay on schedule. Mecanik provides professional &lt;a href="https://mecanik.dev/en/penetration-testing-services/" rel="noopener noreferrer"&gt;penetration testing services&lt;/a&gt; and comprehensive security testing through the &lt;a href="https://mecanik.dev/en/website-security-audit/" rel="noopener noreferrer"&gt;website security audit&lt;/a&gt; page. We specialise in web application security, server hardening, and API compliance audits. Contact us today to schedule your scoping session.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Related reading:&lt;/strong&gt; &lt;a href="https://mecanik.dev/en/posts/website-security-audit-cost-mitigation-guide/" rel="noopener noreferrer"&gt;Website Security Audit: Prevent Enterprise Breaches&lt;/a&gt;, &lt;a href="https://mecanik.dev/en/posts/cyber-essentials-compliance-uk-guide/" rel="noopener noreferrer"&gt;Cyber Essentials Compliance: A UK Vetting Guide 2026&lt;/a&gt;, &lt;a href="https://mecanik.dev/en/posts/penetration-testing-uk-what-to-expect-in-2026/" rel="noopener noreferrer"&gt;Penetration Testing in the UK - What to Expect in 2026&lt;/a&gt; and &lt;a href="https://mecanik.dev/en/posts/types-of-penetration-testing-black-box-white-box-grey-box/" rel="noopener noreferrer"&gt;Types of Penetration Testing: Black, White and Grey Box&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What is the average penetration testing cost uk?&lt;/strong&gt;&lt;br&gt;
The average cost of a penetration test in the UK starts at £3,500 for a simple web application or API and can exceed £15,000 for complex enterprise networks. The final pricing depends on the number of IP addresses, active endpoints, user roles, and compliance requirements.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why do I need a manual penetration test instead of a scanner?&lt;/strong&gt;&lt;br&gt;
Automated scanners only identify known signature patterns. Conversely, a manual penetration test uses ethical hackers to identify complex logic flaws, chain minor issues into critical breaches, and verify access escalation bugs that scanners cannot spot.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How often should a UK business conduct a pen test?&lt;/strong&gt;&lt;br&gt;
UK businesses should conduct a penetration test at least once a year to maintain compliance standards like ISO 27001. Additionally, you should commission a pen test after launching major feature updates, changing database structures, or shifting cloud hosts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is the role of CREST accreditation in pen testing?&lt;/strong&gt;&lt;br&gt;
CREST accreditation verifies that the security agency and its engineers follow strict technical, ethical, and legal guidelines. Hiring a CREST-approved firm is often a requirement to satisfy compliance audits and validate your security posture to enterprise clients.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What happens if the pen test identifies critical vulnerabilities?&lt;/strong&gt;&lt;br&gt;
A professional test report categorises vulnerabilities by severity (Critical, High, Medium, Low). Your development team should patch critical and high risks immediately, and the testing agency should run a validation test to confirm the patches are secure.&lt;/p&gt;

</description>
      <category>security</category>
      <category>cybersecurity</category>
      <category>devops</category>
    </item>
    <item>
      <title>Core Web Vitals in 2026: How to Actually Pass</title>
      <dc:creator>Mecanik1337</dc:creator>
      <pubDate>Fri, 02 Oct 2026 06:00:00 +0000</pubDate>
      <link>https://dev.to/mecanik-dev/core-web-vitals-in-2026-how-to-actually-pass-2cm2</link>
      <guid>https://dev.to/mecanik-dev/core-web-vitals-in-2026-how-to-actually-pass-2cm2</guid>
      <description>&lt;p&gt;Core Web Vitals are Google's measurable signals for real-world page experience, and they feed into ranking. Passing them is not about chasing a green score for its own sake; it is about a site that loads fast, responds instantly, and does not jump around while people use it. This guide explains the three metrics as they stand in 2026 and, more importantly, the fixes that actually move each one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The three Core Web Vitals are LCP (loading), INP (responsiveness), and CLS (visual stability). INP replaced FID as a Core Web Vital in 2024&lt;/li&gt;
&lt;li&gt;"Good" thresholds: LCP under 2.5s, INP under 200ms, CLS under 0.1, measured at the 75th percentile of real visits&lt;/li&gt;
&lt;li&gt;The highest-impact fixes are optimising the largest image or text block, reducing and breaking up JavaScript, and reserving space for images, ads, and embeds&lt;/li&gt;
&lt;li&gt;Use field data (real users), not just lab tests, because Google ranks on real-world performance&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Three Core Web Vitals (2026)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Largest Contentful Paint (LCP): Loading
&lt;/h3&gt;

&lt;p&gt;LCP measures how long it takes for the largest visible element (usually a hero image, banner, or large text block) to render. &lt;strong&gt;Good: under 2.5 seconds.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Interaction to Next Paint (INP): Responsiveness
&lt;/h3&gt;

&lt;p&gt;INP measures how quickly the page responds to user interactions across the whole visit, replacing the older First Input Delay (FID) metric in 2024. It captures the delay between a tap or click and the next visual update. &lt;strong&gt;Good: under 200 milliseconds.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Cumulative Layout Shift (CLS): Visual Stability
&lt;/h3&gt;

&lt;p&gt;CLS measures how much the page unexpectedly shifts while loading (the frustrating jump when a late image or ad pushes content down). &lt;strong&gt;Good: under 0.1.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Google evaluates these at the &lt;strong&gt;75th percentile&lt;/strong&gt; of real visits, so you need most of your users, not just the fastest, to have a good experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fixing LCP
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Optimise the LCP element.&lt;/strong&gt; Identify it (most tools name it) and make it load fast: compress and correctly size the image, serve modern formats (WebP/AVIF), and avoid lazy-loading the hero image.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Serve responsive images&lt;/strong&gt; with a proper &lt;code&gt;srcset&lt;/code&gt; so devices download an appropriately sized file rather than a huge one. (See the guide to &lt;a href="https://mecanik.dev/en/posts/how-to-deal-with-responsive-images/" rel="noopener noreferrer"&gt;dealing with responsive images&lt;/a&gt;.)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Speed up the server response&lt;/strong&gt; (TTFB) with caching and a CDN so the document arrives quickly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Preload critical resources&lt;/strong&gt; (the LCP image, key fonts) and eliminate render-blocking CSS and JavaScript where possible.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use a fast image pipeline.&lt;/strong&gt; Serving images through an optimised service like &lt;a href="https://mecanik.dev/en/posts/cloudflare-image-transformations-resize-and-optimize-on-the-fly/" rel="noopener noreferrer"&gt;Cloudflare image transformations&lt;/a&gt; resizes and compresses on the fly.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Fixing INP
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Reduce JavaScript execution.&lt;/strong&gt; Heavy scripts block the main thread and delay responses. Ship less JavaScript and remove unused code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Break up long tasks.&lt;/strong&gt; Split long-running work so the browser can respond to input between chunks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Defer non-critical work&lt;/strong&gt; until after interaction, and avoid large, synchronous handlers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Audit third-party scripts.&lt;/strong&gt; Tag managers, chat widgets, and analytics are common INP culprits; load them efficiently or remove what you do not need.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Fixing CLS
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Always set width and height&lt;/strong&gt; (or CSS &lt;code&gt;aspect-ratio&lt;/code&gt;) on images and video so the browser reserves space.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reserve space for ads, embeds, and iframes&lt;/strong&gt; so they do not push content when they load.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Avoid inserting content above existing content&lt;/strong&gt; after load.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Preload fonts and use &lt;code&gt;font-display&lt;/code&gt; sensibly&lt;/strong&gt; to reduce layout shift from late-loading fonts.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Measure the Right Way
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Field data over lab data.&lt;/strong&gt; Google ranks on real-user (field) data such as the &lt;a href="https://developer.chrome.com/docs/crux" rel="noopener noreferrer"&gt;Chrome User Experience Report&lt;/a&gt;, not just a single lab run. A perfect lab score with poor field data will not pass.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Watch the 75th percentile.&lt;/strong&gt; Improving your median is not enough; the slower quarter of visits is what fails you.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test on real devices and connections,&lt;/strong&gt; especially mid-range mobile, not just a fast desktop.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The three Core Web Vitals in 2026 are LCP, INP (which replaced FID), and CLS.&lt;/li&gt;
&lt;li&gt;Aim for LCP under 2.5s, INP under 200ms, and CLS under 0.1 at the 75th percentile of real visits.&lt;/li&gt;
&lt;li&gt;The biggest wins: optimise the LCP element and images, cut and split JavaScript for INP, and reserve space to stop layout shift for CLS.&lt;/li&gt;
&lt;li&gt;Judge success on field data, not just a lab score.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Get a Professional Assessment
&lt;/h2&gt;

&lt;p&gt;Core Web Vitals are one part of technical SEO. A &lt;a href="https://mecanik.dev/en/technical-seo-audit/" rel="noopener noreferrer"&gt;technical SEO audit&lt;/a&gt; covers Core Web Vitals alongside crawl budget, indexation, site architecture, JavaScript rendering, and structured data, with a prioritised action plan based on real ranking impact. If speed is your main concern, the guide to &lt;a href="https://mecanik.dev/en/posts/speed-up-your-website-with-cloudflare/" rel="noopener noreferrer"&gt;speeding up your website with Cloudflare&lt;/a&gt; goes deeper on performance.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Related reading:&lt;/strong&gt; &lt;a href="https://mecanik.dev/en/posts/technical-seo-audit-cost-deliverables-pricing/" rel="noopener noreferrer"&gt;Technical SEO Audit Cost: 2026 Price and Deliverables Guide&lt;/a&gt;, &lt;a href="https://mecanik.dev/en/posts/wordpress-performance-audit-core-web-vitals/" rel="noopener noreferrer"&gt;WordPress Performance Audit: Pass Mobile Vitals Guide&lt;/a&gt;, &lt;a href="https://mecanik.dev/en/posts/cloudflare-cdn-caching-core-web-vitals/" rel="noopener noreferrer"&gt;Optimizing Cloudflare CDN Caching Strategy for Speed&lt;/a&gt; and &lt;a href="https://mecanik.dev/en/posts/website-redesign-uk-when-and-how-in-2026/" rel="noopener noreferrer"&gt;Website Redesign UK - When and How in 2026&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Frequently Asked Questions (FAQ)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What are the three Core Web Vitals in 2026?&lt;/strong&gt;&lt;br&gt;
Largest Contentful Paint (LCP) for loading, Interaction to Next Paint (INP) for responsiveness, and Cumulative Layout Shift (CLS) for visual stability. INP replaced First Input Delay (FID) as a Core Web Vital in 2024.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What are good Core Web Vitals scores?&lt;/strong&gt;&lt;br&gt;
LCP under 2.5 seconds, INP under 200 milliseconds, and CLS under 0.1, measured at the 75th percentile of real user visits. You need most visitors, not just the fastest, to hit these.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do Core Web Vitals affect Google rankings?&lt;/strong&gt;&lt;br&gt;
Yes. They are part of Google's page experience signals. They are not the only or the strongest ranking factor, but for competitive queries a good page experience is a meaningful advantage, and a bad one holds you back.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why does my site pass in the lab but fail in Search Console?&lt;/strong&gt;&lt;br&gt;
Because Google uses field data from real users, not a single lab test. Real devices, connections, and the 75th percentile expose problems a fast test machine hides. Optimise for real-world conditions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is the fastest way to improve Core Web Vitals?&lt;/strong&gt;&lt;br&gt;
Usually optimising the LCP element (compress and size the largest image, avoid lazy-loading it) and reducing JavaScript. For CLS, set dimensions on images and reserve space for ads and embeds.&lt;/p&gt;

</description>
      <category>performance</category>
      <category>seo</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Structured Data and Schema Markup for SEO in 2026</title>
      <dc:creator>Mecanik1337</dc:creator>
      <pubDate>Thu, 01 Oct 2026 18:00:00 +0000</pubDate>
      <link>https://dev.to/mecanik-dev/structured-data-and-schema-markup-for-seo-in-2026-2k3c</link>
      <guid>https://dev.to/mecanik-dev/structured-data-and-schema-markup-for-seo-in-2026-2k3c</guid>
      <description>&lt;p&gt;Structured data is how you describe your page to search engines in a language they parse precisely. Instead of hoping Google infers that a page is a recipe, a product, or an FAQ, you tell it explicitly. Done right, this can earn rich results (star ratings, FAQs, prices, and more) that make your listing stand out and win clicks. This guide explains what structured data is, how to implement it in 2026, and where it actually helps.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Structured data is standardised markup (from schema.org) that describes your content to search engines&lt;/li&gt;
&lt;li&gt;Google's recommended format is JSON-LD, a script block you add to the page&lt;/li&gt;
&lt;li&gt;It does not directly boost rankings, but the rich results it can earn improve visibility and click-through rate&lt;/li&gt;
&lt;li&gt;The markup must accurately reflect visible page content, or it breaks Google's guidelines and can be ignored or penalised&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What Structured Data Is
&lt;/h2&gt;

&lt;p&gt;Structured data uses a shared vocabulary, &lt;a href="https://schema.org/" rel="noopener noreferrer"&gt;schema.org&lt;/a&gt;, to label the meaning of content: this is an &lt;code&gt;Article&lt;/code&gt;, that is its &lt;code&gt;author&lt;/code&gt;, this is a &lt;code&gt;Product&lt;/code&gt; with a &lt;code&gt;price&lt;/code&gt; and a &lt;code&gt;review&lt;/code&gt;. Search engines read these labels to understand the page more confidently and to decide whether it is eligible for enhanced search features.&lt;/p&gt;

&lt;h2&gt;
  
  
  JSON-LD Is the Format to Use
&lt;/h2&gt;

&lt;p&gt;There are a few ways to add structured data, but &lt;strong&gt;JSON-LD is Google's recommended format&lt;/strong&gt;. It is a `&lt;/p&gt;

</description>
      <category>seo</category>
      <category>performance</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Technical SEO Audit Checklist for 2026</title>
      <dc:creator>Mecanik1337</dc:creator>
      <pubDate>Thu, 01 Oct 2026 06:00:00 +0000</pubDate>
      <link>https://dev.to/mecanik-dev/technical-seo-audit-checklist-for-2026-677</link>
      <guid>https://dev.to/mecanik-dev/technical-seo-audit-checklist-for-2026-677</guid>
      <description>&lt;p&gt;Content and links get the attention, but if search engines cannot crawl, render, and index your pages efficiently, none of it ranks. A technical SEO audit checks the foundation. This checklist walks through what to review in 2026, grouped by the questions that matter: can Google find your pages, index them, understand them, and does the experience hold up?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A technical SEO audit covers crawlability, indexation, site architecture and internal linking, Core Web Vitals, JavaScript rendering, structured data, and international configuration&lt;/li&gt;
&lt;li&gt;The biggest wins usually come from fixing indexation problems and crawl waste, not from micro-optimisations&lt;/li&gt;
&lt;li&gt;Prioritise findings by ranking impact, not by how many the tool reports&lt;/li&gt;
&lt;li&gt;Re-audit periodically; technical health drifts as the site changes&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  1. Crawlability: Can Google Reach Your Pages?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;robots.txt&lt;/code&gt;:&lt;/strong&gt; Confirm it is not accidentally blocking important pages or resources (CSS/JS Google needs to render).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Crawl budget:&lt;/strong&gt; For large sites, make sure crawlers spend time on valuable pages, not on infinite filters, duplicates, or parameter URLs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;XML sitemap:&lt;/strong&gt; Present, submitted in Search Console, and listing canonical, indexable URLs only.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Broken links and redirects:&lt;/strong&gt; Fix 404s on linked pages and clean up long redirect chains.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;HTTP status codes:&lt;/strong&gt; Ensure pages return the correct codes (200 for live, 301 for permanent moves, 410 for gone).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  2. Indexation: Are the Right Pages Indexed?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Index coverage:&lt;/strong&gt; Review &lt;a href="https://developers.google.com/search/docs/monitor-debug/search-console-start" rel="noopener noreferrer"&gt;Google Search Console&lt;/a&gt; for pages that should be indexed but are not, and pages that are indexed but should not be.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Canonical tags:&lt;/strong&gt; Each piece of content has one clear canonical URL, and canonicals are consistent and self-referencing where appropriate.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;noindex&lt;/code&gt; usage:&lt;/strong&gt; Applied deliberately to thin or duplicate pages, and not accidentally on pages you want to rank.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Duplicate content:&lt;/strong&gt; Consolidate duplicates (HTTP/HTTPS, www/non-www, trailing slashes, parameters) so authority is not split.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  3. Site Architecture and Internal Linking
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Depth:&lt;/strong&gt; Important pages are reachable within a few clicks of the homepage.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Internal linking:&lt;/strong&gt; Link related pages so authority flows to what matters and crawlers can discover everything.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;URL structure:&lt;/strong&gt; Clean, logical, and stable; avoid unnecessary parameters and deep, messy paths.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Orphan pages:&lt;/strong&gt; Find pages with no internal links pointing to them; they are hard to discover and rank.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  4. Performance: Core Web Vitals
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Assess &lt;strong&gt;LCP, INP, and CLS&lt;/strong&gt; on real-user (field) data, not just a lab run.&lt;/li&gt;
&lt;li&gt;Confirm mobile performance specifically, since indexing is mobile-first.&lt;/li&gt;
&lt;li&gt;For the detailed fixes, see the guide to &lt;a href="https://mecanik.dev/en/posts/core-web-vitals-2026-how-to-pass/" rel="noopener noreferrer"&gt;passing Core Web Vitals in 2026&lt;/a&gt; and &lt;a href="https://mecanik.dev/en/posts/speed-up-your-website-with-cloudflare/" rel="noopener noreferrer"&gt;speeding up your website with Cloudflare&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  5. Rendering: Can Google See Your Content?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;JavaScript rendering:&lt;/strong&gt; If content is injected by JavaScript, confirm Google can render and index it. Client-side-only content is a common hidden cause of missing pages.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mobile-first:&lt;/strong&gt; Ensure the mobile version contains the same important content and structured data as desktop.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rendered vs raw HTML:&lt;/strong&gt; Check what Google actually sees after rendering, not just the initial HTML.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  6. Structured Data
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Validate structured data (schema markup) for eligible rich results and fix errors and warnings.&lt;/li&gt;
&lt;li&gt;Ensure markup reflects the visible page content. See the guide to &lt;a href="https://mecanik.dev/en/posts/structured-data-schema-markup-for-seo/" rel="noopener noreferrer"&gt;structured data and schema markup for SEO&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  7. International and Multilingual Configuration
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;hreflang&lt;/code&gt;:&lt;/strong&gt; If you serve multiple languages or regions, confirm &lt;code&gt;hreflang&lt;/code&gt; tags are correct and reciprocal so the right version ranks in the right market.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Geotargeting:&lt;/strong&gt; Check regional targeting settings are consistent.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  8. Security and Fundamentals
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;HTTPS everywhere&lt;/strong&gt;, with HTTP redirecting to HTTPS and no mixed content.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mobile usability:&lt;/strong&gt; No blocked resources, readable text, tappable targets.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Prioritise by Impact
&lt;/h2&gt;

&lt;p&gt;A tool will happily report hundreds of "issues." The skill is separating the handful that actually affect rankings (indexation problems, blocked resources, crawl waste, slow real-world performance) from cosmetic noise. Fix the high-impact items first.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Audit crawlability, indexation, architecture, Core Web Vitals, rendering, structured data, and internationalisation.&lt;/li&gt;
&lt;li&gt;Indexation and crawl-waste fixes usually deliver more than micro-optimisations.&lt;/li&gt;
&lt;li&gt;Judge performance on field data and mobile.&lt;/li&gt;
&lt;li&gt;Prioritise findings by ranking impact, not by raw issue count, and re-audit as the site evolves.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Get a Professional Technical SEO Audit
&lt;/h2&gt;

&lt;p&gt;A checklist gets you oriented; an expert audit tells you what is actually costing you rankings and in what order to fix it. The &lt;a href="https://mecanik.dev/en/technical-seo-audit/" rel="noopener noreferrer"&gt;technical SEO audit service&lt;/a&gt; covers crawl budget, indexation, architecture, rendering, Core Web Vitals, and structured data with a prioritised action plan, and the broader &lt;a href="https://mecanik.dev/en/seo-audit-service/" rel="noopener noreferrer"&gt;SEO audit service&lt;/a&gt; adds on-page, content, and backlink review. For what to expect from SEO support generally, see the guide to &lt;a href="https://mecanik.dev/en/posts/seo-services-uk-what-to-expect-in-2026/" rel="noopener noreferrer"&gt;SEO services in the UK&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Related reading:&lt;/strong&gt; &lt;a href="https://mecanik.dev/en/posts/seo-services-uk-what-to-expect-in-2026/" rel="noopener noreferrer"&gt;SEO Services UK - What to Expect in 2026&lt;/a&gt;, &lt;a href="https://mecanik.dev/en/posts/structured-data-schema-markup-for-seo/" rel="noopener noreferrer"&gt;Structured Data and Schema Markup for SEO in 2026&lt;/a&gt;, &lt;a href="https://mecanik.dev/en/posts/core-web-vitals-2026-how-to-pass/" rel="noopener noreferrer"&gt;Core Web Vitals in 2026: How to Actually Pass&lt;/a&gt; and &lt;a href="https://mecanik.dev/en/posts/generative-engine-optimization-geo-guide/" rel="noopener noreferrer"&gt;Generative Engine Optimization: Future of SEO in 2026&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Frequently Asked Questions (FAQ)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What is a technical SEO audit?&lt;/strong&gt;&lt;br&gt;
A review of the technical foundations that let search engines crawl, render, and index a site: crawlability, indexation, architecture, performance, rendering, structured data, and internationalisation. It finds the infrastructure issues that stop good content from ranking.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How is a technical SEO audit different from an SEO audit?&lt;/strong&gt;&lt;br&gt;
A technical SEO audit focuses on infrastructure and how search engines access the site. A full SEO audit also covers on-page optimisation, content quality, and backlinks. Technical is the foundation the rest builds on.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How often should I run a technical SEO audit?&lt;/strong&gt;&lt;br&gt;
At least once or twice a year for an active site, and after any major change such as a redesign, migration, or platform switch. Technical health drifts as content and code change, so periodic checks catch regressions early.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What technical SEO issues hurt rankings the most?&lt;/strong&gt;&lt;br&gt;
Indexation problems (important pages not indexed, or duplicates splitting authority), blocked resources that stop rendering, crawl waste on low-value URLs, and poor real-world performance. These outweigh most cosmetic issues a tool flags.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I do a technical SEO audit myself?&lt;/strong&gt;&lt;br&gt;
You can cover the basics with Search Console and a crawler, and this checklist helps. Deeper issues like JavaScript rendering, crawl-budget waste, and prioritising by real ranking impact benefit from experience, which is where a professional audit adds value.&lt;/p&gt;

</description>
      <category>seo</category>
      <category>performance</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Website Migration Without Losing Traffic: 2026 Guide</title>
      <dc:creator>Mecanik1337</dc:creator>
      <pubDate>Tue, 22 Sep 2026 18:00:00 +0000</pubDate>
      <link>https://dev.to/mecanik-dev/website-migration-without-losing-traffic-2026-guide-25lk</link>
      <guid>https://dev.to/mecanik-dev/website-migration-without-losing-traffic-2026-guide-25lk</guid>
      <description>&lt;p&gt;A website migration is the only routine project that can wipe out years of search visibility in a single afternoon. Rebuilds, replatforms, domain changes and even a tidy-up of URL structure all carry the same risk, and the damage rarely announces itself on launch day. It shows up two weeks later as a quiet, steady decline that nobody connects to the release.&lt;/p&gt;

&lt;p&gt;The good news is that the causes are well understood and almost entirely preventable. In practice, nearly all migration traffic loss traces back to one thing: an incomplete redirect map. Everything else in this guide is secondary to getting that right.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The one rule:&lt;/strong&gt; Every URL that currently exists and has any value — traffic, backlinks, or indexed status — must resolve to a single permanent redirect pointing at its closest equivalent on the new site. Not the homepage. Not a chain of three hops. One redirect, to the genuinely equivalent page.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Build the Inventory Before You Build Anything
&lt;/h2&gt;

&lt;p&gt;You cannot redirect URLs you do not know about, and no single source lists them all. Pull from four and merge.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A full crawl of the existing site.&lt;/strong&gt; This gives you everything reachable by following links, which is the majority but never the whole picture.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Search Console data.&lt;/strong&gt; Export every URL that has received impressions or clicks. This catches pages that earn traffic but nothing links to internally, which is more common than people expect.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Server access logs.&lt;/strong&gt; These show what is actually being requested, including old URLs that no longer appear anywhere on the site but still receive traffic from bookmarks, emails and external links.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Your backlink data.&lt;/strong&gt; Any URL that other sites link to carries value you will lose if it stops resolving. These are the highest-priority redirects in the whole exercise, because the link equity is not recoverable by other means.&lt;/p&gt;

&lt;p&gt;Merge those four into one list, deduplicate, and you have the real surface area of your site. On a mature site it will be considerably larger than anyone estimated, and that number alone often changes the project plan.&lt;/p&gt;




&lt;h2&gt;
  
  
  Mapping Old to New
&lt;/h2&gt;

&lt;p&gt;With the inventory in hand, the mapping is where judgement enters.&lt;/p&gt;

&lt;p&gt;Map every URL to its closest equivalent. Where a page has a direct replacement, that is easy. Where content has been consolidated, point to the page that now covers the topic. Where content has genuinely gone and has no successor, allow it to return a 404 or 410 rather than redirecting it somewhere irrelevant.&lt;/p&gt;

&lt;p&gt;Resist the temptation to redirect everything to the homepage. Search engines treat a redirect to an unrelated page as a soft 404, so it passes nothing on and produces a poor experience for anyone following an old link. A deliberate 404 on genuinely removed content is a better outcome than a misleading redirect.&lt;/p&gt;

&lt;p&gt;Use permanent redirects, and make sure they are single hops. Redirect chains, where the old URL points to a second URL which points to a third, are common after a site has been migrated more than once. Each hop adds latency and dilutes the signal, so always map to the final destination, not to whatever the previous migration left behind.&lt;/p&gt;

&lt;p&gt;Watch the details that are easy to miss: trailing slashes, uppercase characters, query-string parameters that produce distinct indexed URLs, and the protocol and subdomain. A migration that fixes the pages but leaves &lt;code&gt;http&lt;/code&gt; and &lt;code&gt;www&lt;/code&gt; variants unhandled has doubled its problems.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Else Moves With the Site
&lt;/h2&gt;

&lt;p&gt;Redirects are the biggest risk, but four other things are worth protecting.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Canonical tags and hreflang.&lt;/strong&gt; After migration, canonicals must point at the new URLs. Stale canonicals pointing to the old domain are a genuinely effective way to prevent the new site being indexed at all. If you run multiple languages, every hreflang cluster has to be updated in step, since a mismatch invalidates the whole set.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Structured data.&lt;/strong&gt; Any schema on the old pages should carry across, including URLs inside it. It is easy to migrate the visible content and lose the markup, which quietly removes eligibility for rich results.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Metadata.&lt;/strong&gt; Titles and descriptions should transfer deliberately rather than being regenerated by the new platform's defaults. A rebuild that replaces well-tuned titles with a template pattern will lose clicks even if rankings hold.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Page speed.&lt;/strong&gt; A new site is often heavier than the one it replaced. Since Core Web Vitals are assessed on field data collected over a rolling period, a slower site takes weeks to show its full effect, by which time the cause is easy to misattribute. Our guide to &lt;a href="https://mecanik.dev/en/posts/core-web-vitals-2026-how-to-pass/" rel="noopener noreferrer"&gt;Core Web Vitals&lt;/a&gt; covers what the thresholds actually require.&lt;/p&gt;




&lt;h2&gt;
  
  
  Launch and the First 48 Hours
&lt;/h2&gt;

&lt;p&gt;The launch itself is short; the verification is what matters.&lt;/p&gt;

&lt;p&gt;Before going live, test the redirect map against the full inventory on a staging environment. Automate it: request every old URL, assert a single 301 and the expected destination. Doing this by hand on a sample will miss the pattern that breaks a thousand URLs.&lt;/p&gt;

&lt;p&gt;Confirm the new site is actually crawlable. The most common launch-day disaster is shipping the staging environment's robots directives or a leftover noindex tag. Check both before anything else.&lt;/p&gt;

&lt;p&gt;Submit the new sitemap, and keep the old URLs in a temporary sitemap for a while so crawlers rediscover them and follow the redirects. If the domain changed, use the change of address tool in Search Console.&lt;/p&gt;

&lt;p&gt;Then watch the logs rather than the rankings. Crawler activity on the new URLs tells you within hours whether the migration is being picked up. Rankings tell you nothing useful for at least a week.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Recovery Actually Looks Like
&lt;/h2&gt;

&lt;p&gt;Set expectations before launch, because the shape of the recovery curve causes more panic than the migration itself.&lt;/p&gt;

&lt;p&gt;Some fluctuation is normal even when everything is done correctly. Search engines have to recrawl, reprocess and reassociate every URL, and that takes time proportional to the size of the site. A dip of a couple of weeks on a mid-sized site is not evidence of failure.&lt;/p&gt;

&lt;p&gt;A well-executed migration typically returns to previous levels within four to eight weeks, sometimes faster on smaller sites. A poorly executed one does not recover on its own, because the cause persists.&lt;/p&gt;

&lt;p&gt;The distinction is visible in the data. If Search Console shows a rise in crawl errors and pages dropping out of the index, you have a technical problem to fix. If crawling looks healthy and impressions are simply lagging, you are watching normal reprocessing.&lt;/p&gt;

&lt;p&gt;Keep the old site's analytics and Search Console data exported before launch. Comparing against a baseline you can no longer access is a miserable position, and it happens surprisingly often.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Website Migration Work Costs
&lt;/h2&gt;

&lt;p&gt;Prices reflect typical UK agency rates and scale with URL count rather than page design.&lt;/p&gt;

&lt;p&gt;Redirect mapping and migration QA for a small site of a few hundred URLs generally runs £900 to £2,500. This covers the inventory, the mapping, the automated verification and post-launch checks.&lt;/p&gt;

&lt;p&gt;A mid-sized site of a few thousand URLs typically runs £2,500 to £8,000, mostly because the mapping requires more judgement and the verification more tooling.&lt;/p&gt;

&lt;p&gt;Large or ecommerce sites with faceted navigation, parameter URLs and international variants start around £8,000 and rise with complexity. Faceted navigation in particular can generate enormous numbers of indexed URLs that need decisions rather than mechanical mapping.&lt;/p&gt;

&lt;p&gt;Set against that, the cost of getting it wrong is the revenue from your organic traffic for however long recovery takes, plus the cost of the emergency work to fix it. It is one of the clearer cases for spending money in advance. Our &lt;a href="https://mecanik.dev/en/posts/technical-seo-audit-cost-deliverables-pricing/" rel="noopener noreferrer"&gt;technical SEO audit cost guide&lt;/a&gt; covers the related diagnostic work.&lt;/p&gt;




&lt;h2&gt;
  
  
  Migrate Once, Properly
&lt;/h2&gt;

&lt;p&gt;Mecanik handles migration planning and verification as part of our &lt;a href="https://mecanik.dev/en/technical-seo-audit/" rel="noopener noreferrer"&gt;technical SEO audit&lt;/a&gt; and &lt;a href="https://mecanik.dev/en/services/website-development/" rel="noopener noreferrer"&gt;website development&lt;/a&gt; services. We build the inventory from all four sources, produce the redirect map, automate verification against it, and monitor crawl behaviour through the first weeks after launch.&lt;/p&gt;

&lt;p&gt;We also do this for platform changes specifically, where the URL structure often changes as a side effect of the new system's conventions rather than by anyone's decision. Our &lt;a href="https://mecanik.dev/en/posts/drupal-migration-cost-options-deadlines/" rel="noopener noreferrer"&gt;Drupal migration guide&lt;/a&gt; covers one common version of that, and the same discipline applies to any replatform.&lt;/p&gt;

&lt;p&gt;If a migration has already happened and traffic has dropped, get in touch with the launch date and we will tell you whether it is a redirect problem, an indexing problem, or normal reprocessing.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Related reading:&lt;/strong&gt; &lt;a href="https://mecanik.dev/en/posts/technical-seo-audit-checklist/" rel="noopener noreferrer"&gt;Technical SEO Audit Checklist for 2026&lt;/a&gt;, &lt;a href="https://mecanik.dev/en/posts/website-redesign-uk-when-and-how-in-2026/" rel="noopener noreferrer"&gt;Website Redesign UK - When and How in 2026&lt;/a&gt;, &lt;a href="https://mecanik.dev/en/posts/hire-drupal-developer-rates-skills-vetting/" rel="noopener noreferrer"&gt;Hire a Drupal Developer: Rates, Skills and Vetting&lt;/a&gt; and &lt;a href="https://mecanik.dev/en/posts/seo-services-uk-what-to-expect-in-2026/" rel="noopener noreferrer"&gt;SEO Services UK - What to Expect in 2026&lt;/a&gt;., &lt;a href="https://mecanik.dev/en/posts/how-to-deal-with-font-face/" rel="noopener noreferrer"&gt;How to deal with @font-face&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Why did my traffic drop after a website migration?&lt;/strong&gt;&lt;br&gt;
Most commonly an incomplete redirect map: URLs that had traffic or backlinks now return errors or point somewhere irrelevant. Other frequent causes are a leftover noindex tag from staging, canonicals still pointing at the old domain, and redirect chains that dilute the signal.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Should I redirect old URLs to the homepage?&lt;/strong&gt;&lt;br&gt;
No. Search engines treat a redirect to an unrelated page as a soft 404, so it passes nothing on and frustrates anyone following an old link. Map each URL to its closest genuine equivalent, and let content with no successor return a 404 or 410 instead.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How long does it take to recover rankings after a migration?&lt;/strong&gt;&lt;br&gt;
A well-executed migration typically returns to previous levels within four to eight weeks, faster on smaller sites. Some fluctuation during recrawling is normal. If crawl errors are rising and pages are dropping out of the index, that is a technical fault rather than normal reprocessing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What should I inventory before migrating a website?&lt;/strong&gt;&lt;br&gt;
Merge four sources: a full crawl of the existing site, every URL with impressions or clicks in Search Console, server access logs showing what is genuinely requested, and your backlink data. Each catches URLs the others miss, and backlinked URLs are the highest priority to preserve.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How much does website migration SEO work cost?&lt;/strong&gt;&lt;br&gt;
Redirect mapping and verification for a small site of a few hundred URLs typically costs £900 to £2,500. Mid-sized sites of a few thousand URLs run £2,500 to £8,000, while large or ecommerce sites with faceted navigation and international variants start around £8,000.&lt;/p&gt;

</description>
      <category>seo</category>
      <category>webdev</category>
      <category>performance</category>
    </item>
  </channel>
</rss>
