3 reasons why you should let Google host jQuery for you
AJAX, JavaScript, Performance, jQuery By Dave Ward on December 10th, 2008All too often, I find code similar to this when inspecting the source for public websites that use jQuery:
<script type="text/javascript" src="/js/jQuery.min.js"></script>
If you’re doing this on a public facing* website, you are doing it wrong.
Instead, I urge you to use the Google AJAX Libraries content delivery network to serve jQuery to your users directly from Google’s network of datacenters. Doing so has several advantages over hosting jQuery on your server(s): decreased latency, increased parallelism, and better caching.
In this post, I will expand upon those three benefits of Google’s CDN and show you a couple examples of how you can make use of the service.
* None of this is relevant to internal applications served over a LAN. It would be as likely harm performance as improve it.
Decreased Latency
A CDN — short for Content Delivery Network — distributes your static content across servers in various, diverse physical locations. When a user’s browser resolves the URL for these files, their download will automatically target the closest available server in the network.
In the case of Google’s AJAX Libraries CDN, what this means is that any users not physically near your server will be able to download jQuery faster than if you force them to download it from your arbitrarily located server.
There are a handful of CDN services comparable to Google’s, but it’s hard to beat the price of free! This benefit alone could decide the issue, but there’s even more.
Increased parallelism
To avoid needlessly overloading servers, browsers limit the number of connections that can be made simultaneously. Depending on which browser, this limit may be as low as two connections per hostname.
Using the Google AJAX Libraries CDN eliminates one request to your site, allowing more of your local content to downloaded in parallel. It doesn’t make a gigantic difference for users with a six concurrent connection browser, but for those still running a browser that only allows two, the difference is noticeable.
Better caching
Potentially the greatest (yet least mentioned) benefit of using the Google AJAX Libraries CDN is that your users may not need to download jQuery at all.
No matter how aggressive your caching, if you’re hosting jQuery locally then your users must download it at least once. A user may very well have dozens of identical copies of jQuery-1.3.1.min.js in their browser’s cache, but those duplicate files will be ignored when they visit your site for the first time.
On the other hand, when a browser sees multiple subsequent requests for the same Google hosted version of jQuery, it understands that these requests are for the same file. Not only will Google’s servers return a 304 “Not Modified” response if the file is requested again, but also instructs the browser to cache the file for up to one year.
This means that even if someone visits hundreds of sites using the same Google hosted version of jQuery, they will only have to download it once.
Implementation
By now, you’re probably convinced that the Google AJAX Libraries CDN is the way to go for your public facing sites that use jQuery. So, let me show you how you can put it to use.
Of the two methods available, this option is the one that Google recommends:
The google.load() approach offers the most functionality and performance.
For example:
<script type="text/javascript"
src="http://www.google.com/jsapi"></script>
<script type="text/javascript">
// You may specify partial version numbers, such as "1" or "1.3",
// with the same result. Doing so will automatically load the
// latest version matching that partial revision pattern
// (i.e. both 1 and 1.3 would load 1.3.2 today).
google.load("jquery", "1.3.2");
google.setOnLoadCallback(function() {
// Place init code here instead of $(document).ready()
});
</script>While there’s nothing wrong with this, and it is definitely an improvement over hosting jQuery locally, I don’t agree that it offers the best performance.

As you can see, loading, parsing, and executing jsapi delays the actual jQuery request. Not usually by a very large amount, but it’s an unnecessary delay. Tenths of a second may not seem significant, but they add up very quickly.
Worse, you cannot reliably use a $(document).ready() handler in conjunction with this load method. The setOnLoadCallback() handler is a requirement.
Back to basics
In the face of those drawbacks to the google.load() method, I’d suggest using a good ‘ol fashioned <script> declaration. Google does support this method as well.
For example:
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script> <script type="text/javascript"> $(document).ready(function() { // This is more like it! }); </script>
Not only does this method avoid the jsapi delay, but it also eliminates three unnecessary HTTP requests. I prefer and recommend this method.
Conclusion
According to a recent study, Google will consume 16.5% of all consumer Internet capacity in the United States during 2008. I think it’s fair to say that those guys know how to efficiently serve up some content.
The opportunity to let the pros handle part of your site’s JavaScript footprint free of charge is too good to pass up. As often as even returning users experience the “empty cache” load time of your site, it’s important to take advantage of an easy optimization like this one.
What do you think? Are you using the Google AJAX Libraries CDN on your sites? Can you think of a scenario where the google.load() method would perform better than simple <script> declaration?
Possibly related posts
What do you think? Your comments are welcomed.
I appreciate all of your comments, questions, and other feedback, but please try to stay on topic. If you have a question unrelated to this post, I recommend posting on the ASP.NET forums or Stack Overflow instead.
If you're replying to an existing comment, please use the threading feature. To do this, click the "Reply to this comment" link underneath the comment you're replying to.
Other sites linking to this post
- Host jQuery at Google (with Intellisense support)
- Dew Drop - December 10, 2008 | Alvin Ashcraft's Morning Dew
- rascunho » Blog Archive » links for 2008-12-10
- if(JTeam && Toolman) {blog.read();} » Blog Archive » Javascript libraries hosted by Google
- Looking at Code | Have Google host libraries.
- Let Google host your jquery.js file | eKini: Web Developer Blog
- Coderies | taggle.org
- links for 2008-12-12 « boblog
- Daily Digest for 2008-12-12 | andrew . tj . id . au
- BlogBuzz December 27, 2008
- Quick Tip – let someone else serve your CSS framework
- Google hostet Javascript-Libraries
- Test
- Let Google Host Your jQuery Javascript File at Will Ayers - Design and Programming Blog
- Daily Links | AndySowards.com :: Professional Web Design, Development, Programming, Hacks, Downloads, Math and being a Web 2.0 Hipster?
- Weekly Web Nuggets #42 : Code Monkey Labs
- Event Calendar: Submitting Events » Death of a Gremmie
- Shizzle» Blog Archive » Let Google host jQuery for you
- ghettocooler.net » The Links Have Risen
- Wordpress插件:Use Google Libraries - 苍楼笔记
- Ventajas y desventajas del uso de Google como host de librerías javascript « Gerardo Contijoch
- Carron Media - Extend Google Analytics with jQuery
- DotNetShoutout
- Introducting Typekit | Industrial Brand
- Jaap Vossers’ SharePoint Blog » Using Google Ajax Libraries API to load jQuery
- Code a Tricky Login Form With Sliding Signup with jQuery. | CodeTricky
- Mike Panitz's Blog » Using jQuery with CakePHP: The Basics
- Use Google Libraries | 风云阁

Your comments
We tried to do this, for all the reasons you state. Unfortunately, for the few weeks that we had it that way, our local development internet connection was a bit unpredictable. Every time the internet connection came down, testing ground to a screeching halt; it just wasn’t considered worth it in the end.
There are ways around this. Not certain of which framework you’re using… But in Django you set a debug settings. And you’ve got access to this in your templating framework.
Dave,
The only thing that bugs me about this is that the intellisense in VS2008 doesn’t pick up the google js file. This isn’t a big deal as I just add a local reference for working with it and then remove it before deployment.
Would be good if the intellisense worked on remote JS files.
Jon
If you’re working in JavaScript include files, you can use:
/// <Reference Path="/path/to/jquery-vsdoc.js"/>This is a great post which expands a post I made on my blog called Differences Between Local And Google Hosted jQuery Installations so hopefully anybody who comes here needing help with jQuery on Google will find all the information they need!
Keep up the good work, Ian.
@Paul: When doing development, you should have a local copy anyway IMHO. You’re not developing/testing on your live server are you?
If you’re doing this on a public facing* website, you are doing it wrong…
Strong words.
What if you are serving up content over https?
https://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js
Using the google.load() method will also allow you to use Google’s ClientLocation :)
http://code.google.com/apis/ajax/documentation/#ClientLocation
What if the user’s network (for some reason) is blocking googles CDN.
This could happen if some crazy corporate policy exists, that stops the downloading of some other file on the CDN (or blocking google entirely).
These users will no longer be able to use your site correctly.
I don’t think you’re very likely to find that combination in practice. If they’re willing to block 16.5% of the Internet in one shot, they’ve probably blocked your site too.
I can speak from experience – that this happens.
It’s a royal pain, too.
If you’re coding the site correctly, the experience will degrade but not lose any functionality in this scenario. Since some users turn JS off at the browser level, you should be doing this anyway.
Thanks for the write-up, Dave. I’ve been using the Google hosted jQuery for a while and wondering if I shouldn’t be. Your points remind me why I started doing it in the first place and makes me feel more confident that I should continue doing so.
Couldn’t you use JS to verify google’s jQuery script loaded… Then fallback to a locally hosted version if it’s unavailable?
if(typeof jQuery == ‘undefined’)
{
// load local version….
}
https://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js….
Nice one fella!
My only concern would be breaking changes with a new version. I know, not probable, but definitely possible…….
If you’re using the <script/> method, you don’t have to worry about that. The 1.2.6 URL will always load 1.2.6, even after 1.3 is released.
If you used the google.load() method and didn’t specify the full version explicitly (e.g. “1″ or “1.2″), that could definitely be a problem.
^^^
Over engineering?
This is probably the most worthless thing Google has come up with. Yeah sure it’s nice that they are supporting the libraries, but really, how is this beneficial? All we do to handle the problem you describe in your post is to download the minified versions of all the plugins and then cut and paste the code into one file.
Now we don’t have to worry about sending 15 files across the pipe (we use a lot of plugins) and all we’re really sending is the minified files and our custom javascript file. 2 files and that’s it.
Why would you want to force me to re-download jQuery in your combined include? That’s an unnecessary waste of time and bandwidth.
Script combining is generally a good idea, but rolling jQuery into your monolithic JS include will never match the performance of using Google’s CDN; not even for users with an empty cache.
You’d be very, very surprised at how much it does matter. Rolling it into 1 big JS is the preferred way to package a JS-packed site.
If you roll jQuery and all your plugins into one JS include and I use the Google hosted jQuery in conjunction with a combined include with just my plugins, my site will load faster than yours every single time. Even for users with an empty cache.
I could argue this all day long since you seem overly stuck in your ways, but 95% of the time it’s far faster to roll up your own JS file, jsmin it, and gzip compress it to your users.
Unless you’re running a heavily loaded server (and even then), it would still be faster to load one file then it would to do 2 full remote calls.
Of course the timing is also dependent upon a few things: your distance to the server hosting the files (hops), your connection, the call order, and how loaded your server is.
I’m not a big fan of someone proposing an idea as the one and only way to accomplish something — and all other ways of doing it are wrong (which is basically what you said, exempting LAN of course). Also by comparing via one tool on one browser is the wrong way to go about showing performance gains.
Anyway, I’d suggest you check out some other methods before claiming a dependency as the best way to do it. I call it a dependency because you’re now fully relying on a third-party. There’s many ways to deliver a payload faster — through things such as dynamic JS importing/loading, etc.
For what it’s worth, so you don’t think I’m picking one way of doing things and arbitrarily claiming it’s best, I’ve been testing it both ways for quite awhile. Even using the old Google Code hosted version, which was less optimized for serving users, was faster than rolling it up.
That’s before you even consider the users who will show up and already have it cached locally.
I’d love to see a post making the counterpoint, with numbers. If you made one, I would be happy to link to it from this post, to offer more complete information.
Interesting post.Thanks for sharing this.
One reason not to use it is privacy:
Google will know all of your client’s IP-addresses, referrers, etc. It’s like using google analytics, but only Google seeing your statistics.
In European data protection laws it may even be illegal.
Yeah, that’s one aspect that I’m not crazy about. At this point though, I’ve mostly given up on Google not knowing what’s going on with a public facing site’s traffic.
++
Privacy was my first thought while reading this article. One should try to not give Google more information than absolutely necessary.
That’s not true, given that a client makes a request once a year if the browser keeps the caching contract, i would hardly call it intrusive.
Chances are your clients will be using google to search for stuff more than once a year.
It would still make the request to get the 304, it just wouldn’t secure a data transfer. Google’s servers could still be logging those 304 requests.
Google currently sets an “expires” header of one year in the future on these files. If your browser has cached Google’s jQuery-1.2.6.min.js on the client side and you visit a new site that uses it within a year, the browser doesn’t even have to check for a 304.
If Google really were as prying as some of the more paranoid among us would suggest, then they wouldn’t set that expires header. They’d happily pay the bandwidth bill to log the 304s.
Thanks for this post! But why do you initialize your script with google.setOnLoadCallback() instead of $(document).ready() ?
Because i still use $(document).ready() even when i load jQuery with google’s jsAPI and it works well.
I’ve found that it depends on how fast google.load() loads jQuery and where your $(document).ready() is.
It would probably be of more value if Google also stored copies of frequently used plugins as well as the main jquery file.
Even with the delay, there is one advantage of the google.load() method.
Remember that SCRIPT tags block the download of other components and the loading of the dom. This blocking nature is primarily designed to support document.write() and other synchronous features of the language.
When a script is loaded dynamically, it is not a blocking download. (Document.write is also broken, but you shouldn’t be using that anyhow.)
So, even though the total time for jQuery’s load might be 200ms longer, if the jQuery loading takes a while, then your page is functional that whole time, rather than freezing up waiting for it.
If you’re just including jQuery, a mere 16723 bytes gzipped, it’s probably not too terrible. If you were loading lots of different scripts and modules, or if perceived load time was absolutely critical, then it could be more significant.
Isaac, that’s a great point. Depending on your existing page’s logic, switching to google.load() may or may not be an advantage if you have onload code that (un)intentionally depends on the blocking behavior of regular script tags. Definitely something to consider and test for if making the switch.
It probably bears more thorough testing, but I’ve found that google.load() exhibits the same blocking behavior as a normal script element.
I’m assuming (dangerous!) that google.load() works by injecting a script element via document.createElement(), which would be subject to the same blocking issues.
Hi Dave. But if there truly was blocking with google.load(), then this isn’t consistent with your response to Julien’s comment above where you said “I’ve found that it depends on how fast google.load() loads jQuery and where your $(document).ready() is.” when he asked about why you would need to use setOnLoadCallback() rather than jQuery’s $(document).ready().
I haven’t done any testing, but if there truly was blocking with google.load(), then I’d think there would be no reason you couldn’t use $(document).ready().
Try this, for example:
Attempting to access the jQuery object in the same block as the google.load will fail because jQuery hasn’t had time to load. Yet, if you watch in something like Firebug, the google.load() of jQuery will still block site.js until it completes loading (after the early $ access already threw an error anyway).
Just to underscore this point, this post has been receiving traffic from this search query:
http://www.google.com/search?q=%22%24+is+not+defined%22+jquery+google+ajax+api
So, people are definitely running into this issue in practice.
Hi, thanks
your write but not for all conditions.
read my blog to know why you should not host it on Google.
http://tajary.blogspot.com/2008/12/1-reason-why-you-should-not-let-google.html
thank you
Any comments on this? Seems Google code might be blocked in certain countries. If so, that would be a strong argument against this method. Anyone have more info on this?
Alireza’s problem is due to the US embargo against Iran, as absurd as that is.
Anyone knowledgable as to which countries are blocked from Google code due to this embargo?
Absurd and ridiculous as it may be, it might be a production-stopper if you plan on doing business in any of those countries (and not already hindered from doing so if your company resides in the U.S).
This is a good piece of code for testing. It demonstrates that while loading jQuery via google.load(), the browser will continue to execute/process the page until it hits another piece of external content to retrieve. I do get the “$ is not defined” error.
In contrast, there’s no error when using a script tag for jQuery since the browser completely halts execution of the page until jQuery has fully downloaded and been parsed.
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js"></script> <script type="text/javascript"> $(document).ready(function() { alert("I will run."); }); </script> <script src="/scripts/site.js"></script>But with this, as Isaac pointed out, there may be a small delay in the page fully loading compared to google.load(). Assuming all your onload jQuery logic is currently wrapped up in (document).ready(), switching to Google’s setOnLoadCallback() method seems safe to do. If Google’s CDN serves jQuery quickly, I don’t think I’d be worried about just using the script tag, avoiding google.load().
What’s the recommended pattern for lazy-loading the jquery framework (and associated plugins)? I am thinking of scenarios like webparts, where you require the use of jquery, but don’t want to cause another http request and subsequent parsing of the same library.
You could use something like this before first use of jQuery in each of your webparts:
<script type="text/javascript" src="http://www.google.com/jsapi"></script> <script type="text/javascript"> if (typeof(jQuery) === "undefined") { google.load("jquery", "1.2.6"); } </script> <script type="text/javascript"> // Safe to use jQuery at this point. </script>I’m not sold on benefits of google hosted jquery.
Whats your assumption re your visitors browser cache settings (on/off)
if a majority of your visitors have clear cache sure, CDN hosting of ALL objects would accelerate loads but otherwise, there are basic principles to improving client side render performance without introducing a reliance on an external host..
- use minimized versions of jquery (remove white space, decrease file size)
- gzip (compress whats left to send over wire)
- apache mod_expires (cache for X timeframe)
- host jquery on separate host (deliver static objects and dynamic by separate hosts)
- locate JS files at bottom (prevent script blocking)
- Load all required JS files on early in visit process. don’t double up…Static object loads shouldn’t be coupled with query responses
also worth noting, once you start a browser session and your browser either confirms the objects status’s or redownloads, for the rest of that session, you won’t notice a benefit because user local cache is used for the rest of that session..
Even if you ignore the caching angle, Google’s CDN is going to serve files faster than you will be able to. Their CDN is one of the best in the world. Users potentially hitting the page with it pre-cached is just icing on the cake.
Sure, CDN hosting all static assets is even better, but how many sites really do that? The vast majority of sites in the wild use no CDN.
Even for sites that do use a CDN, using Google’s jQuery is an opportunity for cost cutting and potentially increased parallelism (assuming more than just JS is distributed via CDN).
* gzip (compress whats left to send over wire)
Totally in agreement for this. It really matters a lot compressed and uncompressed scripts.
…but what if the user got this fine plugin named “NoScript”.
NoScript won’t load scripts from other domains as standard – the user have to accept them. :(
are there possibilities like Zach said:
excuse my bad english and greets from northrhine westfalia,
mathias
btw. this is a great article!
This is interesting. What if you are using custom jQuery plugins? Can you still use this method?
Sure. It’s just like using a local copy of jQuery, only faster.
Do you know all those sites that fetch jQuery from Google Dave? Well, 9/10 you will see calls to ajax.googleapis.com that are taking ages to reply, so I think that using a different host to fetch jQuery is slower – overall – than including it from the server that one is already connected to.
I’ve always found the opposite to be the case (Google serves it faster than my servers can). Do you have any examples of sites that hang on the dependency?
Regarding the “$ is not defined” issue when loading using googles ajax method. I use the following and have had 0 issues with it so far…
—————————————
google.setOnLoadCallback(init);
function init() {
$(function() {
//initialise…
});
}
—————————————
So, uh, Google’s having *serious* latency issues (at least from my part of the world), and large and small sites alike that rely on the hosted jquery are hanging completely. Awesome! Granted, this will hopefully happen only rarely, but…
And that’s exactly why I don’t use Google for my jQuery stuff. Local is best. I started seeing issues with Gmail from yesterday onwards. Who knows, maybe their maps are no longer reduce (or the other way round). Again, CDN is nice in theory, but don’t think that it beats local (well, depending on most sites’ target audience).
Looks to have more to do with network routing and less with Google: http://blogs.zdnet.com/BTL/?p=18064
None of my sites were very affected by this. Remember that the CDN hosted files are served with a +1 year expires header. Returning users don’t even require a 304 ping.
It would be a problem for new users, but how many new users (who don’t have access to Google search to find you) affected by the routing issues are you likely to bounce in that couple hour window? It’s a pain, but no where near a catastrophe.
One big surprise is that with Firefox 3 fetching jquery 1.3.2. from Google I get a 200 status code every time instead of 304.
So there is no caching benefit, just the benefit from the CDN.
Can anybody confirm this ?
thanks
Because it’s served with a far-future expires header, you’ll only see a request if your cache doesn’t contain a copy of the file. For up to a year after it’s cached, no request is made at all when the browser encounters a reference to it, not even to check for a 304.
So, the only time you’ll ever see a request, it will have a 200 response. You shouldn’t see subsequent requests (and 200 responses) though, unless something’s preventing your browser from caching the file.
What you mention is true for jquery-1.2.6 but not for 1.3.2
Try the simplest page and check with firebug. If you reload the simple page with 1.2.6 you will see a 304 status code but a 200 status code for 1.3.2:
I think the issue is that the response adds a http header Age not zero which is not included when you request 1.2.6.
Try it! I was quite surprised !
It’s normal to see a 200 response on the first request.
It would be abnormal to see a 304. With a far-future expires header, the browser shouldn’t even be pinging for a 304 if it has it cached.
When it’s being properly cached, you shouldn’t even see it appear in the Firebug net tab.
Sure, the previous post skipped the basic html. I compared a page with jquery 1.2.6 and another with 1.3.2. The page with the old jquery caches properly but not the one with 1.3.2.
At least with firebug 1.3 I see the 304 because if you look at the header responses it returns a Last-Modified, which takes precedence over expires
It takes 5 minutes to do this test in firebug but I assume you haven’t even tested what I am saying.
Your script snippet in Back to Basics references 1.3.2, so you should update the article. I will also try with IE and report the findings.
I use the Google hosted 1.3.2 on several sites. I double checked them this morning, after reading your comment, to make sure it’s still caching properly in Firefox.
It is for me.
The browser never makes a request for jQuery (1.3.2), not even a ping for 304, unless I clear my cache or force an update with a shift/ctrl reload.
I also verified it in Live HTTP headers and Wireshark. Firefox is using the locally cached copy and isn’t sending even a single byte over my connection when it hits a reference to http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js
Do you have a publicly available page that reproduces what you’re seeing? I’ll take a look at it.
Thanks for checking.
My issue is minor, I was refreshing both a page with 1.2.6 and a page with 1.3.2. The page with 1.2.6 checks the 1.2.6 link and gets a 304. The page with 1.3.2 gets a 200
Bravo, Google :)
If you happen to run a WordPress site, there’s a plugin that will easily do this for you, for all available JS libraries:
http://wordpress.org/extend/plugins/use-google-libraries/
Just install and activate. Operation is automatic, no configuration needed.
Thanks for sharing your knowledge!