In this post, I will show you how to “truly” compile Node.js (JavaScript) code to V8 Bytecode. This allows you to hide or protect your source code in a better way than obfuscation or other not-very-efficient tricks (like encrypting your code using a secret key, which will be embedded in your app binaries, that’s why I said “truly” above). So, using bytenode tool, you can distribute a binary version .jsc of your JavaScript files. You can also bundle all your .js files using Browserify, then compile that single file into .jsc. Check on Github. bytenode repository Long story short.. Install bytenode globally: [sudo] npm install -g bytenode To compile your .js file, run this command: bytenode --compile my-file.js my-file.jsc Install bytenode in your project too: npm install --save bytenode In your code, require bytenode, to register extension in Node.js module system. That’s why we installed it locally too. const bytenode = require('bytenode'); .jsc You can now require my-file.jsc as a module: You can also remove from production build. const myFile = require('./my-file.jsc'); my-file.js And if you want to run c using cli: my-file.js bytenode bytenode --run my-file.jsc Now you know how to compile files, how to require the compiled version in your code, and how to run files from the terminal. Let’s move on to the long story. .js .jsc V8 engine (which Node.js is based on) uses what is called: just in time compilation (JIT), where JavaScript code is compiled just before execution, then it will be optimised subsequently. Starting from v5.7.0, the vm module introduced a property called in Constructor function, so if you do something like this: Node.js produceCachedData vm.Script helloScript = vm. ;', { produceCachedData: }); let new Script(' . ( ) console log "Hello World!" true /* This is required for Node.js < 10.0.0 */ View on GitHub Then, get the bytecode or buffer: cachedData helloBuffer = helloScript.cachedData; helloBuffer = helloScript.createCachedData(); let // or in Node.js >= 10 let View on GitHub This can be used to create an identical script that will execute the same instructions when it run, by passing it to the Constructor function: helloBuffer vm.Script anotherHelloScript = vm.Script( , { : , : helloBuffer }); let new '' produceCachedData true cachedData // This will fail! View on GitHub But this will fail, V8 engine will complain about the first argument (that empty string ), when it checks whether it is the same code as the one that was used to generate buffer in the first place. However, this checking process is quite easy, it is the length of the code that does matter. So, this will work: '' helloBuffer anotherHelloScript = vm.Script( .repeat( ), { : , : helloBuffer }); let new ' ' 28 produceCachedData true cachedData View on GitHub We give it an empty string with the same length (28) as the original code ( ) . That’s it! console.log("Hello World!"); This is interesting, using the cached buffer and the original code length we were able to create an identical script. Both scripts can be run using function. So if you ran them: .runInThisContext(); helloScript.runInThisContext(); anotherHelloScript.runInThisContext(); View on GitHub you will see ‘Hello World!’ twice. (Note that if you have used the wrong length, or if you have used another version of Node.js/V8: won’t run, and its property will be set to ). anotherHelloScript cachedDataRejected true Now to our last step, when we defined we used a hard coded value (28) as our code length. How can we change this, so that in the runtime we don’t have to know exactly how long was the original source code? anotherHelloScript After some digging in V8 source code, I have found that the header information is defined (in this file ): here code-serializer.h // The data header consists of uint32_t-sized entries: // [0] magic number and (internally provided) external reference count // [1] version hash // [2] source hash // [3] cpu features // [4] flag hash View on GitHub But, Node.js buffer is Uint8Array typed array. This means that each entry from the array will take four entries in the buffer. So, the payload length (which is hash at index , which is bytes in Node buffer) will be: uint32 uint8 source [2] [8, 9, 10, 11] payloadLengthBytes = whateverBufferYouHave.slice( , ); let 8 12 View on GitHub It will be some thing like this: , which is Little Endian, so it reads: . That is our code length (28 in decimal). <Buffer 1c 00 00 00> 0x0000001c To convert these four bytes to a numeric value, you may do something like this: firstByte + (secodeByte * 256) + (thirdByte * 256**2) + (forthByte * 256**3), Or in a more elegant way, you can do this: length = payloadLengthBytes.reduce( sum += number * **power , ); let ( ) => sum, number, power 256 0 View on GitHub As I did in my library, check it to see the full recipe. here Alternatively, we could use function, which does exactly what we want: buf.readIntLE() length = whateverBufferYouHave.readIntLE( , ); let 8 4 // 8 is the offset, 4 is the number of bytes to read View on GitHub Once you have read the length of the original code (that was used to generate the buffer), you can now create your script: cachedData anotherHelloScript = vm.Script( .repeat(length), { : , : helloBuffer }); anotherHelloScript.runInThisContext(); let new ' ' produceCachedData true cachedData // later in your code View on GitHub Finally, does this technique have an impact on performance? Well, in recent versions of v8 (and Node.js), the performance is almost the same. Using octance benchmark I did not find any difference in performance. I know that Google deprecated octance (because browsers and JS engines were cheating), but the results in our situation are significant, because we are comparing the same code on the same JS engine. So, the final answer is: Bytenode does NOT have a negative impact on performance. Check my , where you can find complete working examples. I have added an (which has no source code protection at all) and for (which has a similar tool nwjc, but it works only with browser-side code). I will add more examples (and tests) soon, hopefully. Github repository example for Electron NW.js