<?xml version="1.0" encoding="utf-8"?>
<feed xml:lang="en-us" xmlns="http://www.w3.org/2005/Atom"><title>Simon Willison's Weblog: nodejs</title><link href="http://simonwillison.net/" rel="alternate"/><link href="http://simonwillison.net/tags/nodejs.atom" rel="self"/><id>http://simonwillison.net/</id><updated>2026-03-22T19:53:00+00:00</updated><author><name>Simon Willison</name></author><entry><title>JavaScript Sandboxing Research</title><link href="https://simonwillison.net/2026/Mar/22/javascript-sandboxing-research/#atom-tag" rel="alternate"/><published>2026-03-22T19:53:00+00:00</published><updated>2026-03-22T19:53:00+00:00</updated><id>https://simonwillison.net/2026/Mar/22/javascript-sandboxing-research/#atom-tag</id><summary type="html">
    
        &lt;p&gt;&lt;strong&gt;Research:&lt;/strong&gt; &lt;a href="https://github.com/simonw/research/tree/main/javascript-sandboxing-research#readme"&gt;JavaScript Sandboxing Research&lt;/a&gt;&lt;/p&gt;
        &lt;p&gt;Aaron Harper &lt;a href="https://www.inngest.com/blog/node-worker-threads"&gt;wrote about Node.js worker threads&lt;/a&gt;, which inspired me to run a research task to see if they might help with running JavaScript in a sandbox. Claude Code went way beyond my initial question and produced a comparison of &lt;a href="https://github.com/laverdet/isolated-vm"&gt;isolated-vm&lt;/a&gt;, &lt;a href="https://github.com/patriksimek/vm2"&gt;vm2&lt;/a&gt;, &lt;a href="https://github.com/justjake/quickjs-emscripten"&gt;quickjs-emscripten&lt;/a&gt;, &lt;a href="https://github.com/quickjs-ng/quickjs"&gt;QuickJS-NG&lt;/a&gt;, &lt;a href="https://github.com/tc39/proposal-shadowrealm"&gt;ShadowRealm&lt;/a&gt;, and &lt;a href="https://docs.deno.com/runtime/manual/runtime/workers/"&gt;Deno Workers&lt;/a&gt;.&lt;/p&gt;
    
    
        &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/javascript"&gt;javascript&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/nodejs"&gt;nodejs&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/sandboxing"&gt;sandboxing&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/claude-code"&gt;claude-code&lt;/a&gt;&lt;/p&gt;
    

</summary><category term="javascript"/><category term="nodejs"/><category term="sandboxing"/><category term="claude-code"/></entry><entry><title>MicroQuickJS</title><link href="https://simonwillison.net/2025/Dec/23/microquickjs/#atom-tag" rel="alternate"/><published>2025-12-23T20:53:40+00:00</published><updated>2025-12-23T20:53:40+00:00</updated><id>https://simonwillison.net/2025/Dec/23/microquickjs/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/bellard/mquickjs"&gt;MicroQuickJS&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
New project from programming legend Fabrice Bellard, of ffmpeg and QEMU and QuickJS and &lt;a href="https://bellard.org"&gt;so much more&lt;/a&gt; fame:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;MicroQuickJS (aka. MQuickJS) is a Javascript engine targetted at embedded systems. It compiles and runs Javascript programs with as low as 10 kB of RAM. The whole engine requires about 100 kB of ROM (ARM Thumb-2 code) including the C library. The speed is comparable to QuickJS.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It supports &lt;a href="https://github.com/bellard/mquickjs/blob/17ce6fe54c1ea4f500f26636bd22058fce2ce61a/README.md#javascript-subset-reference"&gt;a subset of full JavaScript&lt;/a&gt;, though it looks like a rich and full-featured subset to me.&lt;/p&gt;
&lt;p&gt;One of my ongoing interests is sandboxing: mechanisms for executing untrusted code - from end users or generated by LLMs - in an environment that restricts memory usage and applies a strict time limit and restricts file or network access. Could MicroQuickJS be useful in that context?&lt;/p&gt;
&lt;p&gt;I fired up Claude Code for web (on my iPhone) and kicked off &lt;a href="https://simonwillison.net/2025/Nov/6/async-code-research/"&gt;an asynchronous research project&lt;/a&gt; to see explore that question:&lt;/p&gt;
&lt;p&gt;My full prompt &lt;a href="https://github.com/simonw/research/pull/50#issue-3757781692"&gt;is here&lt;/a&gt;. It started like this:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;Clone https://github.com/bellard/mquickjs to /tmp&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Investigate this code as the basis for a safe sandboxing environment for running untrusted code such that it cannot exhaust memory or CPU or access files or the network&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;First try building python bindings for this using FFI - write a script that builds these by checking out the code to /tmp and building against that, to avoid copying the C code in this repo permanently. Write and execute tests with pytest to exercise it as a sandbox&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Then build a "real" Python extension not using FFI and experiment with that&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Then try compiling the C to WebAssembly and exercising it via both node.js and Deno, with a similar suite of tests [...]&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I later added to the interactive session:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;Does it have a regex engine that might allow a resource exhaustion attack from an expensive regex?&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;(The answer was no - the regex engine calls the interrupt handler even during pathological expression backtracking, meaning that any configured time limit should still hold.)&lt;/p&gt;
&lt;p&gt;Here's &lt;a href="https://gistpreview.github.io/?6e07c54db7bb8ed8aa0eccfe4a384679"&gt;the full transcript&lt;/a&gt; and the &lt;a href="https://github.com/simonw/research/blob/main/mquickjs-sandbox/README.md"&gt;final report&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Some key observations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;MicroQuickJS is &lt;em&gt;very&lt;/em&gt; well suited to the sandbox problem. It has robust near and time limits baked in, it doesn't expose any dangerous primitive like filesystem of network access and even has a regular expression engine that protects against exhaustion attacks (provided you configure a time limit).&lt;/li&gt;
&lt;li&gt;Claude span up and tested a Python library that calls a MicroQuickJS shared library (involving a little bit of extra C), a compiled a Python binding and a library that uses the original MicroQuickJS CLI tool. All of those approaches work well.&lt;/li&gt;
&lt;li&gt;Compiling to WebAssembly was a little harder. It got a version working in Node.js and Deno and Pyodide, but the Python libraries wasmer and wasmtime proved harder, apparently because "mquickjs uses setjmp/longjmp for error handling". It managed to get to a working wasmtime version with &lt;a href="https://github.com/simonw/research/blob/main/mquickjs-sandbox/README.md#working-solution"&gt;a gross hack&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I'm really excited about this. MicroQuickJS is tiny, full featured, looks robust and comes from excellent pedigree. I think this makes for a very solid new entrant in the quest for a robust sandbox.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update&lt;/strong&gt;: I had Claude Code build &lt;a href="https://tools.simonwillison.net/microquickjs"&gt;tools.simonwillison.net/microquickjs&lt;/a&gt;, an interactive web playground for trying out the WebAssembly build of MicroQuickJS, adapted from my previous &lt;a href="https://tools.simonwillison.net/quickjs"&gt;QuickJS plaground&lt;/a&gt;. My QuickJS page loads 2.28 MB (675 KB transferred). The MicroQuickJS one loads 303 KB (120 KB transferred).&lt;/p&gt;
&lt;p&gt;Here are &lt;a href="https://github.com/simonw/tools/pull/180#issue-3758595291"&gt;the prompts I used&lt;/a&gt; for that.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/c"&gt;c&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/javascript"&gt;javascript&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/nodejs"&gt;nodejs&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/python"&gt;python&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/regular-expressions"&gt;regular-expressions&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/sandboxing"&gt;sandboxing&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ai"&gt;ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/webassembly"&gt;webassembly&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/deno"&gt;deno&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/pyodide"&gt;pyodide&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/generative-ai"&gt;generative-ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/llms"&gt;llms&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/claude-code"&gt;claude-code&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/fabrice-bellard"&gt;fabrice-bellard&lt;/a&gt;&lt;/p&gt;



</summary><category term="c"/><category term="javascript"/><category term="nodejs"/><category term="python"/><category term="regular-expressions"/><category term="sandboxing"/><category term="ai"/><category term="webassembly"/><category term="deno"/><category term="pyodide"/><category term="generative-ai"/><category term="llms"/><category term="claude-code"/><category term="fabrice-bellard"/></entry><entry><title>My review of Claude's new Code Interpreter, released under a very confusing name</title><link href="https://simonwillison.net/2025/Sep/9/claude-code-interpreter/#atom-tag" rel="alternate"/><published>2025-09-09T18:11:32+00:00</published><updated>2025-09-09T18:11:32+00:00</updated><id>https://simonwillison.net/2025/Sep/9/claude-code-interpreter/#atom-tag</id><summary type="html">
    &lt;p&gt;Today on the Anthropic blog: &lt;strong&gt;&lt;a href="https://www.anthropic.com/news/create-files"&gt;Claude can now create and edit files&lt;/a&gt;&lt;/strong&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Claude can now create and edit Excel spreadsheets, documents, PowerPoint slide decks, and PDFs directly in &lt;a href="https://claude.ai/"&gt;Claude.ai&lt;/a&gt; and the desktop app. [...]&lt;/p&gt;
&lt;p&gt;File creation is now available as a preview for Max, Team, and Enterprise plan users. Pro users will get access in the coming weeks.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Then right at the &lt;em&gt;very end&lt;/em&gt; of their post:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This feature gives Claude internet access to create and analyze files, which may put your data at risk. Monitor chats closely when using this feature. &lt;a href="https://support.anthropic.com/en/articles/12111783-create-and-edit-files-with-claude"&gt;Learn more&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;And tucked away half way down their &lt;a href="https://support.anthropic.com/en/articles/12111783-create-and-edit-files-with-claude"&gt;Create and edit files with Claude&lt;/a&gt; help article:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;With this feature, Claude can also do more advanced data analysis and data science work. Claude can create Python scripts for data analysis. Claude can create data visualizations in image files like PNG. You can also upload CSV, TSV, and other files for data analysis and visualization.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Talk about &lt;a href="https://www.merriam-webster.com/wordplay/bury-the-lede-versus-lead"&gt;burying the lede&lt;/a&gt;... this is their version of &lt;a href="https://simonwillison.net/tags/code-interpreter/"&gt;ChatGPT Code Interpreter&lt;/a&gt;, my all-time favorite feature of ChatGPT!&lt;/p&gt;

&lt;p&gt;Claude can now write and execute custom Python (and Node.js) code in a server-side sandbox and use it to process and analyze data.&lt;/p&gt;
&lt;p&gt;In a particularly egregious example of AI companies being terrible at naming features, the official name for this one really does appear to be &lt;strong&gt;Upgraded file creation and analysis&lt;/strong&gt;. Sigh.&lt;/p&gt;
&lt;p&gt;This is quite a confusing release, because Claude &lt;em&gt;already&lt;/em&gt; had a variant of this feature, &lt;a href="https://www.anthropic.com/news/analysis-tool"&gt;released in October 2024&lt;/a&gt; with the weak but more sensible name &lt;strong&gt;Analysis tool&lt;/strong&gt;. Here are &lt;a href="https://simonwillison.net/2024/Oct/24/claude-analysis-tool/"&gt;my notes from when that came out&lt;/a&gt;. That tool worked by generating and executing JavaScript in the user's own browser.&lt;/p&gt;
&lt;p&gt;The new tool works entirely differently. It's much closer in implementation to OpenAI's Code Interpreter: Claude now has access to a server-side container environment in which it can run shell commands and execute Python and Node.js code to manipulate data and both read and generate files.&lt;/p&gt;
&lt;p&gt;It's worth noting that Anthropic have a similar feature in their API called &lt;a href="https://docs.anthropic.com/en/docs/agents-and-tools/tool-use/code-execution-tool"&gt;Code execution tool&lt;/a&gt;, but today is the first time end-users of Claude have been able to execute arbitrary code in a server-side container.&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href="https://simonwillison.net/2025/Sep/9/claude-code-interpreter/#switching-it-on-in-settings-features"&gt;Switching it on in settings/features&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="https://simonwillison.net/2025/Sep/9/claude-code-interpreter/#exploring-the-environment"&gt;Exploring the environment&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="https://simonwillison.net/2025/Sep/9/claude-code-interpreter/#starting-with-something-easy"&gt;Starting with something easy&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="https://simonwillison.net/2025/Sep/9/claude-code-interpreter/#something-much-harder-recreating-the-ai-adoption-chart"&gt;Something much harder: recreating the AI adoption chart&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="https://simonwillison.net/2025/Sep/9/claude-code-interpreter/#prompt-injection-risks"&gt;Prompt injection risks&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="https://simonwillison.net/2025/Sep/9/claude-code-interpreter/#my-verdict-on-claude-code-interpreter-so-far"&gt;My verdict on Claude Code Interpreter so far&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="https://simonwillison.net/2025/Sep/9/claude-code-interpreter/#ai-labs-find-explaining-this-feature-incredibly-difficult"&gt;AI labs find explaining this feature incredibly difficult&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="switching-it-on-in-settings-features"&gt;Switching it on in settings/features&lt;/h4&gt;
&lt;p&gt;I have a Pro Plan but found the setting to enable it on the &lt;a href="https://claude.ai/settings/features"&gt;claude.ai/settings/features&lt;/a&gt;. It's possible my account was granted early access without me realizing, since the Pro plan isn't supposed to have it yet:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://static.simonwillison.net/static/2025/claude-analysis-toggle.jpg" alt="Experimental. Preview and provide feedback on upcoming enhancements to our platform. Please note: experimental features might influence Claude’s behavior and some interactions may differ from the standard experience. Analysis tool:  Claude can write and run code to process data, run analysis, and produce data visualizations in real time. Upgraded file creation and analysis: Allow Claude to create and edit docs, spreadsheets, presentations, PDFs, and data reports on web and desktop. Does not support versioning or remixing of Artifacts. This feature gives Claude network access to create and analyze files, which has security risks. Monitor chats closely when using this feature. The two features each have a toggle - the toggle for the file creation tool is turned on." style="max-width: 100%;" /&gt;&lt;/p&gt;
&lt;p&gt;Interestingly, toggling on the "Upgraded file creation and analysis" option toggles off the "Analysis tool" option, and vice versa. You can't have both at the same time.&lt;/p&gt;
&lt;p&gt;I guess this is to help reduce confusion? It surprised me though as Claude can sometimes use the existing analysis tool to help it in the creation of artifacts, as I &lt;a href="https://simonwillison.net/2025/Jun/25/ai-powered-apps-with-claude/"&gt;noted here&lt;/a&gt; when I wrote about the Claudeception feature they added in June.&lt;/p&gt;
&lt;h4 id="exploring-the-environment"&gt;Exploring the environment&lt;/h4&gt;
&lt;p&gt;I started by using the tool to explore the tool. Here's my &lt;a href="https://claude.ai/share/d796a596-380c-4db2-847d-2eeedc620bc0"&gt;first transcript&lt;/a&gt; where I simply prompted the following to see what it could figure out about itself:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;Tell me everything you can about your shell and Python environments&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Here's part of the output:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://static.simonwillison.net/static/2025/claude-files-1.jpg" alt="My prompt, then Claude shows: I'll explore my shell and Python environments to give you a comprehensive overview. • Getting system information and OS details • Checking shell type and version • Getting shell info and bash version • Checking Python version and locations - this one is expandedd to show: bash python3 -version &amp;amp;&amp;amp; which python3 &amp;amp;&amp;amp; which python Output Python 3.12.3 /usr/bin/python3 /usr/bin/python" style="max-width: 100%;" /&gt;&lt;/p&gt;
&lt;p&gt;And the key details it returned, each of which I've verified as true by checking the displayed output of the relevant commands:&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;OS&lt;/strong&gt;: Ubuntu 24.04.2 LTS (Noble) running on Linux kernel 4.4.0-&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Architecture&lt;/strong&gt;: x86_64&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Shell&lt;/strong&gt;: GNU Bash 5.2.21(1)-release&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Current User&lt;/strong&gt;: root (with access to /home/claude directory)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Working Directory&lt;/strong&gt;: Currently in root (/), but /home/claude is the main workspace&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Python Version&lt;/strong&gt;: Python 3.12.3&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Python Executable&lt;/strong&gt;: /usr/bin/python3&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Package Manager&lt;/strong&gt;: pip 24.0&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Python Path&lt;/strong&gt;: Standard system locations including:
&lt;ul&gt;
&lt;li&gt;/usr/lib/python3.12 (standard library)&lt;/li&gt;
&lt;li&gt;/usr/local/lib/python3.12/dist-packages (local packages)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Disk Space&lt;/strong&gt;: 4.9GB total, with 4.6GB available&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Memory&lt;/strong&gt;: 9.0GB RAM available, minimal usage currently&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Node.js&lt;/strong&gt;: v18.19.1 available&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;npm&lt;/strong&gt;: Configured with global packages in &lt;code&gt;/home/claude/.npm-global&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;So we have an Ubuntu 24.04.2 container with 9GB of RAM, ~5GB of disk, Python 3.12.3, and Node.js v18.19.1.&lt;/p&gt;
&lt;p&gt;How about network access? I tried the following:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;Can you access the Internet? Can you run curl? How about using Python http to fetch https://latest.datasette.io/fixtures.json ?&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Again, you can see the &lt;a href="https://claude.ai/share/d796a596-380c-4db2-847d-2eeedc620bc0"&gt;detailed output in the transcript&lt;/a&gt;. Claude tried &lt;code&gt;https://latest.datasette.io/fixtures.json&lt;/code&gt; and then &lt;code&gt;https://httpbin.org/json&lt;/code&gt; and got a 403 forbidden error for both, then &lt;code&gt;https://google.com&lt;/code&gt; and got this curious result:&lt;/p&gt;
&lt;div class="highlight highlight-source-shell"&gt;&lt;pre&gt;curl -s -I https://google.com&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Output:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;HTTP/1.1 200 OK
date: Tue, 09 Sep 2025 16:02:17 GMT
server: envoy

HTTP/2 403 
content-length: 13
content-type: text/plain
date: Tue, 09 Sep 2025 16:02:17 GMT
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Claude did note that it can still use the &lt;code&gt;web_fetch&lt;/code&gt; and &lt;code&gt;web_search&lt;/code&gt; containers independently of that container environment, so it should be able to fetch web content using tools running outside of the container and then write it to a file there.&lt;/p&gt;
&lt;p&gt;On a hunch I tried this:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;Run pip install sqlite-utils&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;... and it worked! Claude can &lt;code&gt;pip install&lt;/code&gt; additional packages from &lt;a href="https://pypi.org/"&gt;PyPI&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;A little more poking around revealed the following relevant environment variables:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;HTTPS_PROXY=http://21.0.0.167:15001
no_proxy=localhost,127.0.0.1,169.254.169.254,metadata.google.internal,*.svc.cluster.local,*.local,*.googleapis.com,*.google.com
NO_PROXY=localhost,127.0.0.1,169.254.169.254,metadata.google.internal,*.svc.cluster.local,*.local,*.googleapis.com,*.google.com
https_proxy=http://21.0.0.167:15001
http_proxy=http://21.0.0.167:15001
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So based on an earlier HTTP header there's an &lt;a href="https://www.envoyproxy.io/"&gt;Envoy proxy&lt;/a&gt; running at an accessible port which apparently implements a strict allowlist.&lt;/p&gt;
&lt;p&gt;I later noticed that &lt;a href="https://support.anthropic.com/en/articles/12111783-create-and-edit-files-with-claude#h_0ee9d698a1"&gt;the help page&lt;/a&gt; includes a full description of what's on that allowlist:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Anthropic Services (Explicit)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;api.anthropic.com, statsig.anthropic.com&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Version Control&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;github.com&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Package Managers - JavaScript/Node&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;NPM:&lt;/strong&gt; registry.npmjs.org, npmjs.com, npmjs.org&lt;br /&gt;
&lt;strong&gt;Yarn:&lt;/strong&gt; yarnpkg.com, registry.yarnpkg.com&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Package Managers - Python&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;pypi.org, files.pythonhosted.org, pythonhosted.org&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So it looks like we have a &lt;em&gt;very&lt;/em&gt; similar system to ChatGPT Code Interpreter. The key differences are that Claude's system can install additional Python packages and has Node.js pre-installed.&lt;/p&gt;
&lt;p&gt;One important limitation from the docs:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The maximum file size is 30MB per file for both uploads and downloads.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The ChatGPT &lt;a href="https://help.openai.com/en/articles/8555545-file-uploads-faq"&gt;limit here&lt;/a&gt; is 512MB. I've often uploaded 100MB+ SQLite database files to ChatGPT, so I'm a little disappointed by this lower limit for Claude.&lt;/p&gt;
&lt;h4 id="starting-with-something-easy"&gt;Starting with something easy&lt;/h4&gt;
&lt;p&gt;I grabbed a copy of the SQLite database behind &lt;a href="https://til.simonwillison.net/"&gt;my TILs website&lt;/a&gt; (21.9MB &lt;a href="https://s3.amazonaws.com/til.simonwillison.net/tils.db"&gt;from here&lt;/a&gt;) and uploaded it to Claude, then prompted:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;Use your Python environment to explore this SQLite database and generate a PDF file containing a join diagram of all the tables&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Here's &lt;a href="https://claude.ai/share/f91a95be-0fb0-4e14-b46c-792b47117a3d"&gt;that conversation&lt;/a&gt;. It did an OK job, producing both &lt;a href="https://static.simonwillison.net/static/2025/til_database_join_diagram.pdf"&gt;the PDF&lt;/a&gt; I asked for and a PNG equivalent which looks like this (since created files are not available in shared chats):&lt;/p&gt;
&lt;p&gt;&lt;img src="https://static.simonwillison.net/static/2025/til_database_join_diagram.jpg" alt="Each table gets a box with a name and columns. A set of lines is overlaid which doesn't quite seem to represent the joins in a useful fashion." style="max-width: 100%;" /&gt;&lt;/p&gt;
&lt;p&gt;This isn't an ideal result - those join lines are difficult to follow - but I'm confident I could get from here to something I liked with only a little more prompting. The important thing is that the system clearly works, and can analyze data in uploaded SQLite files and use them to produce images and PDFs.&lt;/p&gt;
&lt;h4 id="something-much-harder-recreating-the-ai-adoption-chart"&gt;Something much harder: recreating the AI adoption chart&lt;/h4&gt;
&lt;p&gt;Thankfully I have a fresh example of a really challenging ChatGPT Code Interpreter task from just last night, which I described in great detail in &lt;a href="https://simonwillison.net/2025/Sep/9/apollo-ai-adoption/"&gt;Recreating the Apollo AI adoption rate chart with GPT-5, Python and Pyodide&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Short version: I took &lt;a href="https://www.apolloacademy.com/ai-adoption-rate-trending-down-for-large-companies/"&gt;this chart&lt;/a&gt; from Apollo Global and asked ChatGPT to recreate it based on a screenshot and an uploaded XLSX file.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://static.simonwillison.net/static/2025/apollo-ai-chart.jpg" alt="AI adoption rates starting to decline for larger firms. A chart of AI adoption rate by firm size. Includes lines for 250+, 100-249, 50-99, 20-49, 10-19, 5-8 and 1-4 sized organizations. Chart starts in November 2023 with percentages ranging from 3 to 5, then all groups grow through August 2025 albeit with the 250+ group having a higher score than the others. That 25+ group peaks in Jul5 2025 at around 14% and then appears to slope slightly downwards to 12% by August. Some of the other lines also start to tip down, though not as much." style="max-width: 100%;" /&gt;&lt;/p&gt;
&lt;p&gt;This time I skipped the bit where I had ChatGPT hunt down the original data and jumped straight to the "recreate this chart" step. I used the exact same prompt as I provided to ChatGPT:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;Use this data to recreate this chart using python&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;And uploaded the same two files - &lt;a href="https://static.simonwillison.net/static/cors-allow/2025/Employment-Size-Class-Sep-2025.xlsx"&gt;this XLSX file&lt;/a&gt; and the &lt;a href="https://static.simonwillison.net/static/2025/apollo-ai-chart.jpg"&gt;screenshot of the original chart&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://static.simonwillison.net/static/2025/claude-files-2.jpg" alt="Claude UI - prompt is &amp;quot;Use this data to recreate this chart using python&amp;quot; - I've selected Sonnet 4 and given it both the XLSX and the screenshot as attachments." style="max-width: 100%;" /&gt;&lt;/p&gt;
&lt;p&gt;Claude wrote and ran a bunch of Python code and produced this:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://static.simonwillison.net/static/2025/claude-attempt-1.jpg" alt="The chart has jagged lines, not smooth ones, but they do appear to show the correct numbers. The title and axis are positioned in ways that overlap other text a bit." style="max-width: 100%;" /&gt;&lt;/p&gt;
&lt;p&gt;That's not a bad first attempt - we'll sort out the jagged lines in a moment. With ChatGPT I later told it to plot a six-survey rolling average (since that's what Apollo had done with theirs), so I ran the exact same prompt against Claude:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;Plot it as a six survey rolling average&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src="https://static.simonwillison.net/static/2025/claude-attempt-2.jpg" alt="The lines are more even now, and appear to match the numbers reported by Apollo. They still have a jagged look to them though." style="max-width: 100%;" /&gt;&lt;/p&gt;
&lt;p&gt;So I told Claude:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;Make those lines less jagged&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This did not do what I wanted:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://static.simonwillison.net/static/2025/claude-attempt-3.jpg" alt="The chart looks mostly the same. The lines are a tiny bit thicker." style="max-width: 100%;" /&gt;&lt;/p&gt;
&lt;p&gt;So I gave it a bit of a hint:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;No not like that, I wanted the lines to be a smooth curve like in the original screenshot - you shouldn't have to use scipy for this or manipulate the data, I'm sure matplotlib can do this already&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;A little bit of sycophancy:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;You're absolutely right! Matplotlib has built-in curve smoothing. I was overcomplicating it. Let me create a version that uses matplotlib's natural curve smoothing capabilities. [...]&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This time it used the &lt;code&gt;antialiased=True&lt;/code&gt; and &lt;code&gt;solid_capstyle='round'&lt;/code&gt; options in matplotlib, which again wasn't what I was after. I tried one more thing:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;I did not mean smooth the rendering of the lines. I meant that I wanted curved and not straight lines between points.&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;(Normally if I have to argue this much with a model I'll start a fresh session and try a different prompting strategy from the start.)&lt;/p&gt;
&lt;p&gt;But this did give me what I was looking for:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://static.simonwillison.net/static/2025/claude-attempt-4.jpg" alt="This time the chart finally has smooth curves between points." style="max-width: 100%;" /&gt;&lt;/p&gt;
&lt;p&gt;Oddly enough my ChatGPT chart suffered from that same overlapping title glitch, so I gave Claude the same prompt I had given ChatGPT:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;fix the chart title, it looks like this:&lt;/code&gt; (with a screenshot)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src="https://static.simonwillison.net/static/2025/claude-attempt-5.jpg" alt="Now the chart shows a clear title at the top saying AI adoption rates starting to decline for larger firms" style="max-width: 100%;" /&gt;&lt;/p&gt;
&lt;p&gt;We got there in the end! I've shared &lt;a href="https://claude.ai/share/cc32d405-cb53-4e52-a1a0-9b4df4e528ac"&gt;the full transcript of the chat&lt;/a&gt;, although frustratingly the images and some of the code may not be visible. I &lt;a href="https://gist.github.com/simonw/806e1aa0e6c29ad64834037f779e0dc0"&gt;created this Gist&lt;/a&gt; with copies of the files that it let me download.&lt;/p&gt;
&lt;h4 id="prompt-injection-risks"&gt;Prompt injection risks&lt;/h4&gt;
&lt;p&gt;ChatGPT Code Interpreter has no access to the internet at all, which limits how much damage an attacker can do if they manage to sneak their own malicious instructions into the model's context.&lt;/p&gt;
&lt;p&gt;Since Claude Code Interpreter (I'm &lt;em&gt;not&lt;/em&gt; going to be calling it "Upgraded file creation and analysis"!) has a limited form of internet access, we need to worry about &lt;a href="https://simonwillison.net/2025/Jun/16/the-lethal-trifecta/"&gt;lethal trifecta&lt;/a&gt; and other prompt injection attacks.&lt;/p&gt;
&lt;p&gt;The &lt;a href="https://support.anthropic.com/en/articles/12111783-create-and-edit-files-with-claude#h_0ee9d698a1"&gt;help article&lt;/a&gt; actually covers this in some detail:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;It is possible for a bad actor to inconspicuously add instructions via external files or websites that trick Claude into:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Downloading and running untrusted code in the sandbox environment for malicious purposes.&lt;/li&gt;
&lt;li&gt;Reading sensitive data from a &lt;a href="http://claude.ai"&gt;claude.ai&lt;/a&gt; connected knowledge source (e.g., Remote MCP, projects) and using the sandbox environment to make an external network request to leak the data.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This means Claude can be tricked into sending information from its context (e.g., prompts, projects, data via MCP, Google integrations) to malicious third parties. To mitigate these risks, we recommend you monitor Claude while using the feature and stop it if you see it using or accessing data unexpectedly.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;"We recommend you monitor Claude while using the feature" smells me to me like unfairly outsourcing the problem to Anthropic's users, but I'm not sure what more they can do!&lt;/p&gt;
&lt;p&gt;It's interesting that they still describe the external communication risk even though they've locked down a lot of network access. My best guess is that they know that allowlisting &lt;code&gt;github.com&lt;/code&gt; opens an &lt;em&gt;enormous&lt;/em&gt; array of potential exfiltration vectors.&lt;/p&gt;
&lt;p&gt;Anthropic also note:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;We have performed red-teaming and security testing on the feature. We have a continuous process for ongoing security testing and red-teaming of this feature.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I plan to be cautious using this feature with any data that I very much don't want to be leaked to a third party, if there's even the slightest chance that a malicious instructions might sneak its way in.&lt;/p&gt;
&lt;h4 id="my-verdict-on-claude-code-interpreter-so-far"&gt;My verdict on Claude Code Interpreter so far&lt;/h4&gt;
&lt;p&gt;I'm generally very excited about this. Code Interpreter has been my most-valued LLM feature since it launched in early 2023, and the Claude version includes some upgrades on the original - package installation, Node.js support - that I expect will be very useful.&lt;/p&gt;
&lt;p&gt;I don't particularly mark it down for taking a little more prompting to recreate the Apollo chart than ChatGPT did. For one thing I was using Claude Sonnet 4 - I expect Claude Opus 4.1 would have done better. I also have a much stronger intuition for Code Interpreter prompts that work with GPT-5.&lt;/p&gt;
&lt;p&gt;I don't think my chart recreation exercise here should be taken as showing any meaningful differences between the two.&lt;/p&gt;
&lt;h4 id="ai-labs-find-explaining-this-feature-incredibly-difficult"&gt;AI labs find explaining this feature incredibly difficult&lt;/h4&gt;
&lt;p&gt;I find it &lt;em&gt;fascinating&lt;/em&gt; how difficult the AI labs find describing this feature to people! OpenAI went from "Code Interpreter" to "Advanced Data Analysis" and maybe back again? It's hard to even find their official landing page for that feature now. (I &lt;a href="https://chatgpt.com/share/68c070ff-fe9c-8006-91b5-cff799253836"&gt;got GPT-5 to look for it&lt;/a&gt; and it hunted for 37 seconds and settled on the help page for &lt;a href="https://help.openai.com/en/articles/8437071-data-analysis-with-chatgpt"&gt;Data analysis with ChatGPT&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Anthropic already used the bad name "Analysis tool" for a different implementation, and now have the somehow-worse name "Upgraded file creation and analysis". Their launch announcement avoids even talking about code execution, focusing exclusively on the tool's ability to generate spreadsheets and PDFs!&lt;/p&gt;
&lt;p&gt;I wonder if any of the AI labs will crack the code on how to name and explain this thing? I feel like it's still a very under-appreciated feature of LLMs, despite having been around for more than two years now.&lt;/p&gt;
    
        &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/nodejs"&gt;nodejs&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/python"&gt;python&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/visualization"&gt;visualization&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ai"&gt;ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/openai"&gt;openai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/prompt-injection"&gt;prompt-injection&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/generative-ai"&gt;generative-ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/chatgpt"&gt;chatgpt&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/llms"&gt;llms&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ai-assisted-programming"&gt;ai-assisted-programming&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/anthropic"&gt;anthropic&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/claude"&gt;claude&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/code-interpreter"&gt;code-interpreter&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/llm-tool-use"&gt;llm-tool-use&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/vibe-coding"&gt;vibe-coding&lt;/a&gt;&lt;/p&gt;
    

</summary><category term="nodejs"/><category term="python"/><category term="visualization"/><category term="ai"/><category term="openai"/><category term="prompt-injection"/><category term="generative-ai"/><category term="chatgpt"/><category term="llms"/><category term="ai-assisted-programming"/><category term="anthropic"/><category term="claude"/><category term="code-interpreter"/><category term="llm-tool-use"/><category term="vibe-coding"/></entry><entry><title>The many, many, many JavaScript runtimes of the last decade</title><link href="https://simonwillison.net/2025/Jul/27/javascript-runtimes-of-the-last-decade/#atom-tag" rel="alternate"/><published>2025-07-27T23:56:57+00:00</published><updated>2025-07-27T23:56:57+00:00</updated><id>https://simonwillison.net/2025/Jul/27/javascript-runtimes-of-the-last-decade/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://buttondown.com/whatever_jamie/archive/the-many-many-many-javascript-runtimes-of-the-last-decade/"&gt;The many, many, many JavaScript runtimes of the last decade&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Extraordinary piece of writing by Jamie Birch who spent over a year putting together this comprehensive reference to JavaScript runtimes. It covers everything from Node.js, Deno, Electron, AWS Lambda, Cloudflare Workers and Bun all the way to much smaller projects idea like dukluv and txiki.js.

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://news.ycombinator.com/item?id=44701574"&gt;Hacker News&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/javascript"&gt;javascript&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/nodejs"&gt;nodejs&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/deno"&gt;deno&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/bun"&gt;bun&lt;/a&gt;&lt;/p&gt;



</summary><category term="javascript"/><category term="nodejs"/><category term="deno"/><category term="bun"/></entry><entry><title>ccusage</title><link href="https://simonwillison.net/2025/Jul/14/ccusage/#atom-tag" rel="alternate"/><published>2025-07-14T16:59:24+00:00</published><updated>2025-07-14T16:59:24+00:00</updated><id>https://simonwillison.net/2025/Jul/14/ccusage/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/ryoppippi/ccusage"&gt;ccusage&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Claude Code logs detailed usage information to the &lt;code&gt;~/.claude/&lt;/code&gt; directory. ccusage is a neat little Node.js tool which reads that information and shows you a readable summary of your usage patterns, including the estimated cost in USD per day.&lt;/p&gt;
&lt;p&gt;You can run it using npx like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npx ccusage@latest
&lt;/code&gt;&lt;/pre&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/javascript"&gt;javascript&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/nodejs"&gt;nodejs&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/anthropic"&gt;anthropic&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/claude-code"&gt;claude-code&lt;/a&gt;&lt;/p&gt;



</summary><category term="javascript"/><category term="nodejs"/><category term="anthropic"/><category term="claude-code"/></entry><entry><title>Using Rust in non-Rust servers to improve performance</title><link href="https://simonwillison.net/2024/Oct/23/using-rust-in-non-rust-servers/#atom-tag" rel="alternate"/><published>2024-10-23T15:45:42+00:00</published><updated>2024-10-23T15:45:42+00:00</updated><id>https://simonwillison.net/2024/Oct/23/using-rust-in-non-rust-servers/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/pretzelhammer/rust-blog/blob/master/posts/rust-in-non-rust-servers.md"&gt;Using Rust in non-Rust servers to improve performance&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Deep dive into different strategies for optimizing part of a web server application - in this case written in Node.js, but the same strategies should work for Python as well - by integrating with Rust in different ways.&lt;/p&gt;
&lt;p&gt;The example app renders QR codes, initially using the pure JavaScript &lt;a href="https://www.npmjs.com/package/qrcode"&gt;qrcode&lt;/a&gt; package. That ran at 1,464 req/sec, but switching it to calling a tiny Rust CLI wrapper around the &lt;a href="https://crates.io/crates/qrcode"&gt;qrcode crate&lt;/a&gt; using Node.js &lt;code&gt;spawn()&lt;/code&gt; increased that to 2,572 req/sec.&lt;/p&gt;
&lt;p&gt;This is yet another reminder to me that I need to get over my &lt;code&gt;cgi-bin&lt;/code&gt; era bias that says that shelling out to another process during a web request is a bad idea. It turns out modern computers can quite happily spawn and terminate 2,500+ processes a second!&lt;/p&gt;
&lt;p&gt;The article optimizes further first through a Rust library compiled to WebAssembly (2,978 req/sec) and then through a Rust function exposed to Node.js as a native library (5,490 req/sec), then finishes with a full Rust rewrite of the server that replaces Node.js entirely, running at 7,212 req/sec.&lt;/p&gt;
&lt;p&gt;Full source code to accompany the article is available in the &lt;a href="https://github.com/pretzelhammer/using-rust-in-non-rust-servers"&gt;using-rust-in-non-rust-servers&lt;/a&gt; repository.

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://lobste.rs/s/slviv2/using_rust_non_rust_servers_improve"&gt;lobste.rs&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/javascript"&gt;javascript&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/nodejs"&gt;nodejs&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/performance"&gt;performance&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/scaling"&gt;scaling&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/rust"&gt;rust&lt;/a&gt;&lt;/p&gt;



</summary><category term="javascript"/><category term="nodejs"/><category term="performance"/><category term="scaling"/><category term="rust"/></entry><entry><title>Announcing Deno 2</title><link href="https://simonwillison.net/2024/Oct/10/announcing-deno-2/#atom-tag" rel="alternate"/><published>2024-10-10T04:11:02+00:00</published><updated>2024-10-10T04:11:02+00:00</updated><id>https://simonwillison.net/2024/Oct/10/announcing-deno-2/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://deno.com/blog/v2.0"&gt;Announcing Deno 2&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
The big focus of Deno 2 is compatibility with the existing Node.js and npm ecosystem:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Deno 2 takes all of the features developers love about Deno 1.x — zero-config, all-in-one toolchain for JavaScript and TypeScript development, web standard API support, secure by default — and makes it fully backwards compatible with Node and npm (in ESM).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The npm support &lt;a href="https://docs.deno.com/runtime/fundamentals/node/#using-npm-packages"&gt;is documented here&lt;/a&gt;. You can write a script like this:&lt;/p&gt;
&lt;div class="highlight highlight-source-js"&gt;&lt;pre&gt;&lt;span class="pl-k"&gt;import&lt;/span&gt; &lt;span class="pl-c1"&gt;*&lt;/span&gt; &lt;span class="pl-k"&gt;as&lt;/span&gt; &lt;span class="pl-s1"&gt;emoji&lt;/span&gt; &lt;span class="pl-k"&gt;from&lt;/span&gt; &lt;span class="pl-s"&gt;"npm:node-emoji"&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;
&lt;span class="pl-smi"&gt;console&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;log&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s1"&gt;emoji&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;emojify&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s"&gt;`:sauropod: :heart:  npm`&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And when you run it Deno will automatically fetch and cache the required dependencies:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;deno run main.js
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Another new feature that caught my eye was this:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;deno jupyter&lt;/code&gt; now supports outputting images, graphs, and HTML&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Deno has apparently shipped with &lt;a href="https://docs.deno.com/runtime/reference/cli/jupyter/"&gt;a Jupyter notebook kernel&lt;/a&gt; for a while, and it's had a major upgrade in this release.&lt;/p&gt;
&lt;p&gt;Here's &lt;a href="https://www.youtube.com/watch?v=d35SlRgVxT8&amp;amp;t=1829s"&gt;Ryan Dahl's demo&lt;/a&gt; of the new notebook support in his Deno 2 release video.&lt;/p&gt;
&lt;p&gt;I tried this out myself, and it's really neat. First you need to install the kernel:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;deno juptyer --install
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I was curious to find out what this actually did, so I dug around &lt;a href="https://github.com/denoland/deno/blob/251840a60d1e2ba4ceca85029bd8cc342b6cd038/cli/tools/jupyter/install.rs#L48-L57"&gt;in the code&lt;/a&gt; and then further &lt;a href="https://github.com/runtimed/runtimed/blob/e2cd9b1d88e44842e1b1076d3a1d1f202fcf7879/runtimelib/src/jupyter/dirs.rs#L81-L99"&gt;in the Rust runtimed dependency&lt;/a&gt;. It turns out installing Jupyter kernels, at least on macOS, involves creating a directory in &lt;code&gt;~/Library/Jupyter/kernels/deno&lt;/code&gt; and writing a &lt;code&gt;kernel.json&lt;/code&gt; file containing the following:&lt;/p&gt;
&lt;div class="highlight highlight-source-json"&gt;&lt;pre&gt;{
  &lt;span class="pl-ent"&gt;"argv"&lt;/span&gt;: [
    &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;/opt/homebrew/bin/deno&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;,
    &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;jupyter&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;,
    &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;--kernel&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;,
    &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;--conn&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;,
    &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;{connection_file}&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;
  ],
  &lt;span class="pl-ent"&gt;"display_name"&lt;/span&gt;: &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;Deno&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;,
  &lt;span class="pl-ent"&gt;"language"&lt;/span&gt;: &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;typescript&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;That file is picked up by any Jupyter servers running on your machine, and tells them to run &lt;code&gt;deno jupyter --kernel ...&lt;/code&gt; to start a kernel.&lt;/p&gt;
&lt;p&gt;I started Jupyter like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;jupyter-notebook /tmp
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then started a new notebook, selected the Deno kernel and it worked as advertised:&lt;/p&gt;
&lt;p&gt;&lt;img alt="Jupyter notebook running the Deno kernel. I run 4 + 5 and get 9, then Deno.version and get back 2.0.0. I import Observable Plot and the penguins data, then render a plot which shows as a scatter chart." src="https://static.simonwillison.net/static/2024/deno-jupyter.jpg" /&gt;&lt;/p&gt;
&lt;div class="highlight highlight-source-ts"&gt;&lt;pre&gt;&lt;span class="pl-k"&gt;import&lt;/span&gt; &lt;span class="pl-c1"&gt;*&lt;/span&gt; &lt;span class="pl-k"&gt;as&lt;/span&gt; &lt;span class="pl-smi"&gt;Plot&lt;/span&gt; &lt;span class="pl-k"&gt;from&lt;/span&gt; &lt;span class="pl-s"&gt;"npm:@observablehq/plot"&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;
&lt;span class="pl-k"&gt;import&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt; &lt;span class="pl-smi"&gt;document&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt; &lt;span class="pl-s1"&gt;penguins&lt;/span&gt; &lt;span class="pl-kos"&gt;}&lt;/span&gt; &lt;span class="pl-k"&gt;from&lt;/span&gt; &lt;span class="pl-s"&gt;"jsr:@ry/jupyter-helper"&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;
&lt;span class="pl-k"&gt;let&lt;/span&gt; &lt;span class="pl-s1"&gt;p&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-k"&gt;await&lt;/span&gt; &lt;span class="pl-en"&gt;penguins&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;

&lt;span class="pl-smi"&gt;Plot&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;plot&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-kos"&gt;{&lt;/span&gt;
  &lt;span class="pl-c1"&gt;marks&lt;/span&gt;: &lt;span class="pl-kos"&gt;[&lt;/span&gt;
    &lt;span class="pl-smi"&gt;Plot&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;dot&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s1"&gt;p&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;toRecords&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt;
      &lt;span class="pl-c1"&gt;x&lt;/span&gt;: &lt;span class="pl-s"&gt;"culmen_depth_mm"&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
      &lt;span class="pl-c1"&gt;y&lt;/span&gt;: &lt;span class="pl-s"&gt;"culmen_length_mm"&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
      &lt;span class="pl-c1"&gt;fill&lt;/span&gt;: &lt;span class="pl-s"&gt;"species"&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
    &lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
  &lt;span class="pl-kos"&gt;]&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
  document&lt;span class="pl-kos"&gt;,&lt;/span&gt;
&lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/javascript"&gt;javascript&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/nodejs"&gt;nodejs&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/npm"&gt;npm&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/jupyter"&gt;jupyter&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/typescript"&gt;typescript&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/deno"&gt;deno&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/observable-plot"&gt;observable-plot&lt;/a&gt;&lt;/p&gt;



</summary><category term="javascript"/><category term="nodejs"/><category term="npm"/><category term="jupyter"/><category term="typescript"/><category term="deno"/><category term="observable-plot"/></entry><entry><title>openai/openai-realtime-console</title><link href="https://simonwillison.net/2024/Oct/9/openai-realtime-console/#atom-tag" rel="alternate"/><published>2024-10-09T00:38:38+00:00</published><updated>2024-10-09T00:38:38+00:00</updated><id>https://simonwillison.net/2024/Oct/9/openai-realtime-console/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/openai/openai-realtime-console"&gt;openai/openai-realtime-console&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
I got this OpenAI demo repository working today - it's an &lt;em&gt;extremely&lt;/em&gt; easy way to get started playing around with the new Realtime voice API they announced &lt;a href="https://simonwillison.net/2024/Oct/2/not-digital-god/#gpt-4o-audio-via-the-new-websocket-realtime-api"&gt;at DevDay&lt;/a&gt; last week:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cd /tmp
git clone https://github.com/openai/openai-realtime-console
cd openai-realtime-console
npm i
npm start
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That starts a &lt;code&gt;localhost:3000&lt;/code&gt; server running the demo React application. It asks for an API key, you paste one in and you can start talking to the web page.&lt;/p&gt;
&lt;p&gt;The demo handles voice input, voice output and basic tool support - it has a tool that can show you the weather anywhere in the world, including panning a map to that location. I tried &lt;a href="https://github.com/simonw/openai-realtime-console/commit/c62ac1351be0bf0ab07c5308603b944b9eeb9e1f"&gt;adding a show_map() tool&lt;/a&gt; so I could pan to a location just by saying "Show me a map of the capital of Morocco" - all it took was editing the &lt;code&gt;src/pages/ConsolePage.tsx&lt;/code&gt; file and hitting save, then refreshing the page in my browser to pick up the new function.&lt;/p&gt;
&lt;p&gt;Be warned, it can be quite expensive to play around with. I was testing the application intermittently for only about 15 minutes and racked up $3.87 in API charges.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/javascript"&gt;javascript&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/nodejs"&gt;nodejs&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/websockets"&gt;websockets&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ai"&gt;ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/react"&gt;react&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/openai"&gt;openai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/generative-ai"&gt;generative-ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/llms"&gt;llms&lt;/a&gt;&lt;/p&gt;



</summary><category term="javascript"/><category term="nodejs"/><category term="websockets"/><category term="ai"/><category term="react"/><category term="openai"/><category term="generative-ai"/><category term="llms"/></entry><entry><title>The first four Val Town runtimes</title><link href="https://simonwillison.net/2024/Feb/8/the-first-four-val-town-runtimes/#atom-tag" rel="alternate"/><published>2024-02-08T18:38:39+00:00</published><updated>2024-02-08T18:38:39+00:00</updated><id>https://simonwillison.net/2024/Feb/8/the-first-four-val-town-runtimes/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://blog.val.town/blog/first-four-val-town-runtimes/"&gt;The first four Val Town runtimes&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Val Town solves one of my favourite technical problems: how to run untrusted code in a safe sandbox. They're on their fourth iteration of this now, currently using a Node.js application that launches Deno sub-processes using the &lt;a href="https://github.com/casual-simulation/node-deno-vm"&gt;node-deno-vm&lt;/a&gt; npm package and runs code in those, taking advantage of the Deno sandboxing mechanism and terminating processes that take too long in order to protect against &lt;code&gt;while(true)&lt;/code&gt; style attacks.

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://twitter.com/tmcw/status/1755616125474504960"&gt;@tmcw&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/javascript"&gt;javascript&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/nodejs"&gt;nodejs&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/sandboxing"&gt;sandboxing&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/deno"&gt;deno&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/tom-macwright"&gt;tom-macwright&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/val-town"&gt;val-town&lt;/a&gt;&lt;/p&gt;



</summary><category term="javascript"/><category term="nodejs"/><category term="sandboxing"/><category term="deno"/><category term="tom-macwright"/><category term="val-town"/></entry><entry><title>Making SQLite extensions npm install'able for Node.js, and on deno.land/x for Deno</title><link href="https://simonwillison.net/2023/Mar/29/sqlite-extensions-npm-installable/#atom-tag" rel="alternate"/><published>2023-03-29T22:13:21+00:00</published><updated>2023-03-29T22:13:21+00:00</updated><id>https://simonwillison.net/2023/Mar/29/sqlite-extensions-npm-installable/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://observablehq.com/@asg017/making-sqlite-extensions-npm-installable-and-deno"&gt;Making SQLite extensions npm install&amp;#x27;able for Node.js, and on deno.land/x for Deno&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Alex Garcia figured out how to get his “pip install X” trick for distributing compiled SQLite extensions to work for Node too! Now you can “npm install” 10 of his extensions, including sqlite-regex and sqlite-xsv and sqlite-http and sqlite-html and more, and attach them to a node-sqlite3 or better-sqlite3 connection. He’s bundled them for Deno too!

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://datasette.io/discord"&gt;Datasette Discord&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/nodejs"&gt;nodejs&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/sqlite"&gt;sqlite&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/npm"&gt;npm&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/deno"&gt;deno&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/alex-garcia"&gt;alex-garcia&lt;/a&gt;&lt;/p&gt;



</summary><category term="nodejs"/><category term="sqlite"/><category term="npm"/><category term="deno"/><category term="alex-garcia"/></entry><entry><title>A framework for building Open Graph images</title><link href="https://simonwillison.net/2021/Jun/22/open-graph-images/#atom-tag" rel="alternate"/><published>2021-06-22T21:25:13+00:00</published><updated>2021-06-22T21:25:13+00:00</updated><id>https://simonwillison.net/2021/Jun/22/open-graph-images/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.blog/2021-06-22-framework-building-open-graph-images/"&gt;A framework for building Open Graph images&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
GitHub’s new social preview images are generated by a Node.js script that fetches data from their GraphQL API, generates an HTML version of the card and then grabs a PNG snapshot of it using Puppeteer. It takes an average of 280ms to serve an image and generates around 2 million unique images a day. Interestingly, they found that bumping the available RAM from 512MB up to 513MB had a big effect on performance, because Chromium detects devices on 512MB or less and switches some processes from parallel to sequential.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/github"&gt;github&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/nodejs"&gt;nodejs&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/puppeteer"&gt;puppeteer&lt;/a&gt;&lt;/p&gt;



</summary><category term="github"/><category term="nodejs"/><category term="puppeteer"/></entry><entry><title>Deno 1.0</title><link href="https://simonwillison.net/2020/May/13/deno-10/#atom-tag" rel="alternate"/><published>2020-05-13T23:38:27+00:00</published><updated>2020-05-13T23:38:27+00:00</updated><id>https://simonwillison.net/2020/May/13/deno-10/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://deno.land/v1"&gt;Deno 1.0&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Deno is a new take on server-side JavaScript from a team lead by Ryan Dahl, who originally created Node.js. It’s built using Rust and crammed with fascinating ideas—like the ability to import code directly from a URL.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/javascript"&gt;javascript&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/nodejs"&gt;nodejs&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ryan-dahl"&gt;ryan-dahl&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/rust"&gt;rust&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/deno"&gt;deno&lt;/a&gt;&lt;/p&gt;



</summary><category term="javascript"/><category term="nodejs"/><category term="ryan-dahl"/><category term="rust"/><category term="deno"/></entry><entry><title>elasticsearch-dump</title><link href="https://simonwillison.net/2018/Apr/9/elasticsearch-dump/#atom-tag" rel="alternate"/><published>2018-04-09T22:10:36+00:00</published><updated>2018-04-09T22:10:36+00:00</updated><id>https://simonwillison.net/2018/Apr/9/elasticsearch-dump/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/taskrabbit/elasticsearch-dump"&gt;elasticsearch-dump&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Neat open source utility by TaskRabbit for importing and exporting data in bulk from Elasticsearch. It can copy data from one Elasticsearch cluster directly to another or to an intermediary file, making it a swiss-army knife for migrating data around. I successfully used the “docker run” incantation to execute it without needing to worry about having the correct version of Node.js installed.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/elasticsearch"&gt;elasticsearch&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/nodejs"&gt;nodejs&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/docker"&gt;docker&lt;/a&gt;&lt;/p&gt;



</summary><category term="elasticsearch"/><category term="nodejs"/><category term="docker"/></entry><entry><title>github-trending-repos</title><link href="https://simonwillison.net/2018/Feb/23/github-trending-repos/#atom-tag" rel="alternate"/><published>2018-02-23T17:36:41+00:00</published><updated>2018-02-23T17:36:41+00:00</updated><id>https://simonwillison.net/2018/Feb/23/github-trending-repos/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/vitalets/github-trending-repos"&gt;github-trending-repos&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
This is a really clever hack: Vitaliy Potapov built a system for subscribing to a weekly digest of trending GitHub repos in your favourite languages entirely on top of the existing GitHub issues notification system. Find the issue for your particular language and hit “subscribe” and you’ll get an email (or push notification depending on how you get your issue notifications) once a week with the latest trends. The implementation is a 220 line Node.js script which runs on a daily and weekly schedule using Circle CI, so Vitaliy doesn’t even have to host or pay for any of the underlying infrastructure. It’s brilliant.

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://news.ycombinator.com/item?id=16446250"&gt;Show HN&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/github"&gt;github&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/nodejs"&gt;nodejs&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/github-issues"&gt;github-issues&lt;/a&gt;&lt;/p&gt;



</summary><category term="github"/><category term="nodejs"/><category term="github-issues"/></entry><entry><title>Building a Full-Text Search App Using Docker and Elasticsearch</title><link href="https://simonwillison.net/2018/Feb/1/docker-elasticsearch/#atom-tag" rel="alternate"/><published>2018-02-01T15:41:03+00:00</published><updated>2018-02-01T15:41:03+00:00</updated><id>https://simonwillison.net/2018/Feb/1/docker-elasticsearch/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://blog.patricktriest.com/text-search-docker-elasticsearch/"&gt;Building a Full-Text Search App Using Docker and Elasticsearch&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Deep, comprehensive tutorial from Patrick Triest showing how to use docker-compose to run three containers (Node API, nginx static content, elasticsearch) and then use that to build a neat Vue.js web search UI against 100 books from Project Gutenberg.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/elasticsearch"&gt;elasticsearch&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/nodejs"&gt;nodejs&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/docker"&gt;docker&lt;/a&gt;&lt;/p&gt;



</summary><category term="elasticsearch"/><category term="nodejs"/><category term="docker"/></entry><entry><title>now-ab</title><link href="https://simonwillison.net/2017/Nov/16/now-ab/#atom-tag" rel="alternate"/><published>2017-11-16T23:03:55+00:00</published><updated>2017-11-16T23:03:55+00:00</updated><id>https://simonwillison.net/2017/Nov/16/now-ab/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/sergiodxa/now-ab"&gt;now-ab&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Intriguing example of a Zeit Now microservice: now-ab is a Node.js HTTP proxy which proxies through to one of two or more other Now-deployed applications based on a cookie. If you don’t have the cookie, it picks a backend at random and sets the cookie. Admittedly this is the easiest part of implementing A/B testing (the hard part is the analytics: tracking exposures and conversions) but as an example of a microservice architectural pattern this is fascinating.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/ab-testing"&gt;ab-testing&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/nodejs"&gt;nodejs&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/zeit-now"&gt;zeit-now&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/microservices"&gt;microservices&lt;/a&gt;&lt;/p&gt;



</summary><category term="ab-testing"/><category term="nodejs"/><category term="zeit-now"/><category term="microservices"/></entry><entry><title>ZEIT – 6x Faster Now Uploads with HTTP/2</title><link href="https://simonwillison.net/2017/Nov/8/zeit-http2/#atom-tag" rel="alternate"/><published>2017-11-08T01:04:56+00:00</published><updated>2017-11-08T01:04:56+00:00</updated><id>https://simonwillison.net/2017/Nov/8/zeit-http2/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://zeit.co/blog/http2-uploads"&gt;ZEIT – 6x Faster Now Uploads with HTTP/2&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Fantastic optimization write-up by Pranay Prakash. The Now deployment tool works by computing a hash for every local file in a project, then uploading just the ones that are missing. Pranay switched to uploading over HTTP/2 using the fetch-h2 library and got a 6x speedup for larger projects.

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://twitter.com/rauchg/status/928045524430635008"&gt;Guillermo Rauch&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/nodejs"&gt;nodejs&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/zeit-now"&gt;zeit-now&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/http2"&gt;http2&lt;/a&gt;&lt;/p&gt;



</summary><category term="nodejs"/><category term="zeit-now"/><category term="http2"/></entry><entry><title>Live htop</title><link href="https://simonwillison.net/2017/Nov/1/theden0xfee1deadtop-live-htop/#atom-tag" rel="alternate"/><published>2017-11-01T18:07:10+00:00</published><updated>2017-11-01T18:07:10+00:00</updated><id>https://simonwillison.net/2017/Nov/1/theden0xfee1deadtop-live-htop/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/theden/0xfee1dead.top"&gt;Live htop&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Neat, simplest-thing-that-could-possibly-work implementation of a tool that continually pipes the output of the htop command to a browser over a WebSocket. The htopgen.sh scripts loops every 2 seconds, runs htop, pipes it through a utility to convert the output to HTML and writes that to a file. Then the server.js Node.js script watches for changes to that file and pipes the entire file contents to the browser via socket.io. The index.html page in the browser subscribes to the WebSocket and updates the entire page using innerHTML every time it receives an event.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/nodejs"&gt;nodejs&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/websockets"&gt;websockets&lt;/a&gt;&lt;/p&gt;



</summary><category term="nodejs"/><category term="websockets"/></entry><entry><title>Carbon</title><link href="https://simonwillison.net/2017/Oct/19/carbon/#atom-tag" rel="alternate"/><published>2017-10-19T18:31:47+00:00</published><updated>2017-10-19T18:31:47+00:00</updated><id>https://simonwillison.net/2017/Oct/19/carbon/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://carbon.now.sh/"&gt;Carbon&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Beautiful little tool that you can paste source code into to generate an image of that code with syntax highlighting applied, ready to be tweeted or shared anywhere that lets you share an image. Built in Node and next.js, with image generation handled client-side by the dom-to-image JavaScript library which loads HTML into a SVG foreignObject (sadly not yet supported by Safari) and uses that to populate a canvas and produce a PNG.

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://twitter.com/rauchg/status/921031246385262592"&gt;Guillermo Rauch&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/javascript"&gt;javascript&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/nodejs"&gt;nodejs&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/svg"&gt;svg&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/zeit-now"&gt;zeit-now&lt;/a&gt;&lt;/p&gt;



</summary><category term="javascript"/><category term="nodejs"/><category term="svg"/><category term="zeit-now"/></entry><entry><title>How does one decide which Javascript framework (e.g. Node, Backbone, Angular) to use on any given project?</title><link href="https://simonwillison.net/2014/Mar/11/how-does-one-decide/#atom-tag" rel="alternate"/><published>2014-03-11T17:08:00+00:00</published><updated>2014-03-11T17:08:00+00:00</updated><id>https://simonwillison.net/2014/Mar/11/how-does-one-decide/#atom-tag</id><summary type="html">
    &lt;p&gt;&lt;em&gt;My answer to &lt;a href="https://www.quora.com/How-does-one-decide-which-Javascript-framework-e-g-Node-Backbone-Angular-to-use-on-any-given-project/answer/Simon-Willison"&gt;How does one decide which Javascript framework (e.g. Node, Backbone, Angular) to use on any given project?&lt;/a&gt; on Quora&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If you are just learning JavaScript, I suggest trying to work without any frameworks or libraries at all. Starting with something like Angular will make it much harder for you to learn the core language and browser APIs.&lt;/p&gt;

&lt;p&gt;Once you've worked with raw JavaScript for a while, it's worth starting to learn jQuery - it's the basis of most of the popular JavaScript frameworks out there and understanding how it works will help reinforce a bunch of core JavaScript concepts.&lt;/p&gt;

&lt;p&gt;If your priority is learning though, it's a good idea to start without jQuery. There are a surprising number of JavaScript developers out there who only really know how to program JavaScript using jQuery.&lt;/p&gt;
    
        &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/frameworks"&gt;frameworks&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/javascript"&gt;javascript&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/nodejs"&gt;nodejs&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/programming"&gt;programming&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/webapps"&gt;webapps&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/web-development"&gt;web-development&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/quora"&gt;quora&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/angular"&gt;angular&lt;/a&gt;&lt;/p&gt;
    

</summary><category term="frameworks"/><category term="javascript"/><category term="nodejs"/><category term="programming"/><category term="webapps"/><category term="web-development"/><category term="quora"/><category term="angular"/></entry><entry><title>In simple terms, what is node.js?</title><link href="https://simonwillison.net/2014/Jan/22/in-simple-terms-what/#atom-tag" rel="alternate"/><published>2014-01-22T12:48:00+00:00</published><updated>2014-01-22T12:48:00+00:00</updated><id>https://simonwillison.net/2014/Jan/22/in-simple-terms-what/#atom-tag</id><summary type="html">
    &lt;p&gt;&lt;em&gt;My answer to &lt;a href="https://www.quora.com/In-simple-terms-what-is-node-js?no_redirect=1"&gt;In simple terms, what is node.js?&lt;/a&gt; on Quora&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;It's server-side programming, like PHP. The language you write the server-side code in is JavaScript (specifically the JavaScript version supported by Google's V8 JavaScript engine, which was originally written for the Chrome web browser).&lt;/p&gt;
    
        &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/javascript"&gt;javascript&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/nodejs"&gt;nodejs&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/programming-languages"&gt;programming-languages&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/web-development"&gt;web-development&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/quora"&gt;quora&lt;/a&gt;&lt;/p&gt;
    

</summary><category term="javascript"/><category term="nodejs"/><category term="programming-languages"/><category term="web-development"/><category term="quora"/></entry><entry><title>Does Go have an equivalent node.js's NPM?</title><link href="https://simonwillison.net/2014/Jan/1/does-go-have-an/#atom-tag" rel="alternate"/><published>2014-01-01T13:22:00+00:00</published><updated>2014-01-01T13:22:00+00:00</updated><id>https://simonwillison.net/2014/Jan/1/does-go-have-an/#atom-tag</id><summary type="html">
    &lt;p&gt;&lt;em&gt;My answer to &lt;a href="https://www.quora.com/Does-Go-have-an-equivalent-node-jss-NPM/answer/Simon-Willison"&gt;Does Go have an equivalent node.js&amp;#39;s NPM?&lt;/a&gt; on Quora&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Sort of. Go ships with a command that can download and compile a dependency for your project ("go get &lt;span&gt;&lt;a href="http://github.com/russross/blackfriday"&gt;github.com/russross/blackfriday&lt;/a&gt;&lt;/span&gt;") but it doesn't have a solution for library versioning yet (as far as I can tell).&lt;/p&gt;

&lt;span&gt;&lt;a href="http://golang.org/doc/code.html"&gt;http://golang.org/doc/code.html&lt;/a&gt;&lt;/span&gt; is a useful guide to how Go's development workflow works.
    
        &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/go"&gt;go&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/nodejs"&gt;nodejs&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/quora"&gt;quora&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/npm"&gt;npm&lt;/a&gt;&lt;/p&gt;
    

</summary><category term="go"/><category term="nodejs"/><category term="quora"/><category term="npm"/></entry><entry><title>What is currently the best technology stack for web scraping?</title><link href="https://simonwillison.net/2013/Dec/10/what-is-currently-the/#atom-tag" rel="alternate"/><published>2013-12-10T17:32:00+00:00</published><updated>2013-12-10T17:32:00+00:00</updated><id>https://simonwillison.net/2013/Dec/10/what-is-currently-the/#atom-tag</id><summary type="html">
    &lt;p&gt;&lt;em&gt;My answer to &lt;a href="https://www.quora.com/What-is-currently-the-best-technology-stack-for-web-scraping/answer/Simon-Willison"&gt;What is currently the best technology stack for web scraping?&lt;/a&gt; on Quora&lt;/em&gt;&lt;/p&gt;

&lt;span&gt;&lt;a href="http://phantomjs.org/"&gt;PhantomJS&lt;/a&gt;&lt;/span&gt; combined with &lt;span&gt;&lt;a href="http://casperjs.org/"&gt;CasperJS&lt;/a&gt;&lt;/span&gt; is pretty fantastic - it runs a full, headless copy of a Webkit browser so it can operate against a real DOM, execute JavaScript properly, even grab full rendered screenshots of areas of the page but is still easy to automate.
    
        &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/nodejs"&gt;nodejs&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/webapps"&gt;webapps&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/quora"&gt;quora&lt;/a&gt;&lt;/p&gt;
    

</summary><category term="nodejs"/><category term="webapps"/><category term="quora"/></entry><entry><title>Should a beginner to web development start out with Node.Js?</title><link href="https://simonwillison.net/2013/Sep/9/should-a-beginner-to/#atom-tag" rel="alternate"/><published>2013-09-09T18:00:00+00:00</published><updated>2013-09-09T18:00:00+00:00</updated><id>https://simonwillison.net/2013/Sep/9/should-a-beginner-to/#atom-tag</id><summary type="html">
    &lt;p&gt;&lt;em&gt;My answer to &lt;a href="https://www.quora.com/Should-a-beginner-to-web-development-start-out-with-Node-Js/answer/Simon-Willison"&gt;Should a beginner to web development start out with Node.Js?&lt;/a&gt; on Quora&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Maybe. One of the things I like about Node.js is that the raw abstraction it provides over HTTP is much closer to how the actual protocol works than the abstractions  provided many of the more widely used frameworks such as PHP, Django or Rails. That might actually make it an effective learning tool - I'd be interested in hearing from some web developers who learnt Node.js as their first server-side technology.&lt;/p&gt;
    
        &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/frameworks"&gt;frameworks&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/javascript"&gt;javascript&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/nodejs"&gt;nodejs&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/programming"&gt;programming&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/webapps"&gt;webapps&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/web-development"&gt;web-development&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/quora"&gt;quora&lt;/a&gt;&lt;/p&gt;
    

</summary><category term="frameworks"/><category term="javascript"/><category term="nodejs"/><category term="programming"/><category term="webapps"/><category term="web-development"/><category term="quora"/></entry><entry><title>How do I choose between asynchronous web frameworks? My tech group is fairly language agnostic and we're trying to standardize on some technologies.</title><link href="https://simonwillison.net/2013/Jul/31/how-do-i-choose/#atom-tag" rel="alternate"/><published>2013-07-31T10:15:00+00:00</published><updated>2013-07-31T10:15:00+00:00</updated><id>https://simonwillison.net/2013/Jul/31/how-do-i-choose/#atom-tag</id><summary type="html">
    &lt;p&gt;&lt;em&gt;My answer to &lt;a href="https://www.quora.com/How-do-I-choose-between-asynchronous-web-frameworks-My-tech-group-is-fairly-language-agnostic-and-were-trying-to-standardize-on-some-technologies/answer/Simon-Willison"&gt;How do I choose between asynchronous web frameworks? My tech group is fairly language agnostic and we&amp;#39;re trying to standardize on some technologies.&lt;/a&gt; on Quora&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Since they are all pretty close to each other and it sounds like your tech group's skills would support any of them, I would suggest having your tram build a simple prototype in all three so you can compare them for your own particular team and situation.&lt;/p&gt;
    
        &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/frameworks"&gt;frameworks&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/javascript"&gt;javascript&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/nodejs"&gt;nodejs&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/play"&gt;play&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/python"&gt;python&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/scala"&gt;scala&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/tornado"&gt;tornado&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/webapps"&gt;webapps&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/quora"&gt;quora&lt;/a&gt;&lt;/p&gt;
    

</summary><category term="frameworks"/><category term="javascript"/><category term="nodejs"/><category term="play"/><category term="python"/><category term="scala"/><category term="tornado"/><category term="webapps"/><category term="quora"/></entry><entry><title>What are the design mistakes in the Meteor framework?</title><link href="https://simonwillison.net/2013/Jul/14/what-are-the-design/#atom-tag" rel="alternate"/><published>2013-07-14T15:13:00+00:00</published><updated>2013-07-14T15:13:00+00:00</updated><id>https://simonwillison.net/2013/Jul/14/what-are-the-design/#atom-tag</id><summary type="html">
    &lt;p&gt;&lt;em&gt;My answer to &lt;a href="https://www.quora.com/What-are-the-design-mistakes-in-the-Meteor-framework/answer/Simon-Willison"&gt;What are the design mistakes in the Meteor framework?&lt;/a&gt; on Quora&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Treating the non-JavaScript case as unimportant.&lt;/p&gt;
    
        &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/javascript"&gt;javascript&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/nodejs"&gt;nodejs&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/quora"&gt;quora&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/meteor"&gt;meteor&lt;/a&gt;&lt;/p&gt;
    

</summary><category term="javascript"/><category term="nodejs"/><category term="quora"/><category term="meteor"/></entry><entry><title>How do I get started with node.js?</title><link href="https://simonwillison.net/2013/Mar/22/how-do-i-get/#atom-tag" rel="alternate"/><published>2013-03-22T09:01:00+00:00</published><updated>2013-03-22T09:01:00+00:00</updated><id>https://simonwillison.net/2013/Mar/22/how-do-i-get/#atom-tag</id><summary type="html">
    &lt;p&gt;&lt;em&gt;My answer to &lt;a href="https://www.quora.com/How-do-I-get-started-with-node-js?no_redirect=1"&gt;How do I get started with node.js?&lt;/a&gt; on Quora&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;You don't run Node.js in a script tag on your website. Node is a technology for writing servers in JavaScript - you can think of it as a replacement/alternative for PHP, Python, Ruby, ASP.NET etc.&lt;/p&gt;

&lt;p&gt;This looks like a reasonable getting started guide: &lt;span&gt;&lt;a href="http://www.nodebeginner.org/"&gt;http://www.nodebeginner.org/&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
    
        &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/javascript"&gt;javascript&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/nodejs"&gt;nodejs&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/web-development"&gt;web-development&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/quora"&gt;quora&lt;/a&gt;&lt;/p&gt;
    

</summary><category term="javascript"/><category term="nodejs"/><category term="web-development"/><category term="quora"/></entry><entry><title>Why is node.js so much faster?</title><link href="https://simonwillison.net/2013/Jan/1/why-is-nodejs-so/#atom-tag" rel="alternate"/><published>2013-01-01T17:36:00+00:00</published><updated>2013-01-01T17:36:00+00:00</updated><id>https://simonwillison.net/2013/Jan/1/why-is-nodejs-so/#atom-tag</id><summary type="html">
    &lt;p&gt;&lt;em&gt;My answer to &lt;a href="https://www.quora.com/Why-is-node-js-so-much-faster/answer/Simon-Willison"&gt;Why is node.js so much faster?&lt;/a&gt; on Quora&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;There are two main reasons.&lt;/p&gt;

&lt;p&gt;Firstly, Node runs on top of Google's V8 JIT-compiled JavaScript engine, originally written for Chrome, which is extremely fast for an implementation of a dynamic language (faster than any of the various Ruby implementations).&lt;/p&gt;

&lt;p&gt;Secondly, Node emphasises callback-based asynchronous IO and makes it very hard to make blocking calls. For web apps that spend most of their time waiting on network or database connections this can be a lot more efficient: &lt;span&gt;&lt;a href="http://code.danyork.com/2011/01/25/node-js-doctors-offices-and-fast-food-restaurants-understanding-event-driven-programming/"&gt;http://code.danyork.com/2011/01/...&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Ruby can do asynchronous IO using EventMachine or similar but you have to specifically work for it - with Node you get that behaviour by default.&lt;/p&gt;
    
        &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/javascript"&gt;javascript&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/nodejs"&gt;nodejs&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/quora"&gt;quora&lt;/a&gt;&lt;/p&gt;
    

</summary><category term="javascript"/><category term="nodejs"/><category term="quora"/></entry><entry><title>What are the differences between node.js and websockets?</title><link href="https://simonwillison.net/2012/Oct/1/what-are-the-differences/#atom-tag" rel="alternate"/><published>2012-10-01T13:30:00+00:00</published><updated>2012-10-01T13:30:00+00:00</updated><id>https://simonwillison.net/2012/Oct/1/what-are-the-differences/#atom-tag</id><summary type="html">
    &lt;p&gt;&lt;em&gt;My answer to &lt;a href="https://www.quora.com/What-are-the-differences-between-node-js-and-websockets/answer/Simon-Willison"&gt;What are the differences between node.js and websockets?&lt;/a&gt; on Quora&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This is like asking "what's the difference between PHP and HTTP". Node.js is a technology framework you write code in. WebSockets is a protocol which can be implemented using a technology framework. You can use Node.js to implement the server-side aspect of WebSockets.&lt;/p&gt;
    
        &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/frameworks"&gt;frameworks&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/nodejs"&gt;nodejs&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/websockets"&gt;websockets&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/quora"&gt;quora&lt;/a&gt;&lt;/p&gt;
    

</summary><category term="frameworks"/><category term="nodejs"/><category term="websockets"/><category term="quora"/></entry><entry><title>How difficult is to to learn a language framework, like node.js?</title><link href="https://simonwillison.net/2012/Sep/28/how-difficult-is-to/#atom-tag" rel="alternate"/><published>2012-09-28T13:04:00+00:00</published><updated>2012-09-28T13:04:00+00:00</updated><id>https://simonwillison.net/2012/Sep/28/how-difficult-is-to/#atom-tag</id><summary type="html">
    &lt;p&gt;&lt;em&gt;My answer to &lt;a href="https://www.quora.com/How-difficult-is-to-to-learn-a-language-framework-like-node-js/answer/Simon-Willison"&gt;How difficult is to to learn a language framework, like node.js?&lt;/a&gt; on Quora&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The answer varies enormously depending on the language and the framework. Some frameworks are very easy to pick up, others are harder.&lt;/p&gt;

&lt;p&gt;Node.js is an interesting example, because there's a LOT of stuff you need to understand in order to learn Node effectively.&lt;/p&gt;

&lt;p&gt;If you've already done web programming in a language like PHP or Python you'll have a solid understanding of at least some of the concepts (though Node's model is radically different from something like PHP so there will still be a steep learning curve).&lt;/p&gt;

&lt;p&gt;If you've never done server-side web programming at all you're in for a shock... you'll need to develop an understanding of the HTTP protocol, asynchronous-IO, data storage mechanisms, cookies... lots of concepts which it can take a long time to master (and which Node won't really help you learn, since its documentation is aimed at more experienced developers).&lt;/p&gt;
    
        &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/javascript"&gt;javascript&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/nodejs"&gt;nodejs&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/programming-languages"&gt;programming-languages&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/web-development"&gt;web-development&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/quora"&gt;quora&lt;/a&gt;&lt;/p&gt;
    

</summary><category term="javascript"/><category term="nodejs"/><category term="programming-languages"/><category term="web-development"/><category term="quora"/></entry></feed>