diff --git a/crates/wasm-bindgen-cli-support/src/js.rs b/crates/wasm-bindgen-cli-support/src/js.rs
index a772f82e..c95d1be9 100644
--- a/crates/wasm-bindgen-cli-support/src/js.rs
+++ b/crates/wasm-bindgen-cli-support/src/js.rs
@@ -1044,9 +1044,12 @@ impl<'a, 'b> SubContext<'a, 'b> {
         for f in self.program.exports.iter() {
             self.generate_export(f);
         }
-        for f in self.program.imports.iter() {
+        for f in self.program.imported_functions.iter() {
             self.generate_import(f);
         }
+        for f in self.program.imported_fields.iter() {
+            self.generate_import_field(f);
+        }
         for e in self.program.enums.iter() {
             self.generate_enum(e);
         }
@@ -1319,6 +1322,24 @@ impl<'a, 'b> SubContext<'a, 'b> {
         (format!("{} {}", prefix, dst), format!("{} {}", prefix, dst_ts))
     }
 
+    pub fn generate_import_field(&mut self, import: &shared::ImportField) {
+        let name = import.shim_name();
+        self.cx.imports_to_rewrite.insert(name.clone());
+
+        if let Some(ref module) = import.module {
+            self.cx.imports.push_str(&format!("
+                import {{ {} }} from '{}';
+            ", import.name, module));
+        }
+
+        self.cx.expose_add_heap_object();
+        self.cx.globals.push_str(&format!("
+            export function {}() {{
+                return addHeapObject({});
+            }}
+        ", name, import.name));
+    }
+
     pub fn generate_import(&mut self, import: &shared::Import) {
         if let Some(ref module) = import.module {
             let name_to_import = import.class.as_ref().unwrap_or(&import.function.name);
diff --git a/crates/wasm-bindgen-macro/src/ast.rs b/crates/wasm-bindgen-macro/src/ast.rs
index 11089b97..c4fc5cf8 100644
--- a/crates/wasm-bindgen-macro/src/ast.rs
+++ b/crates/wasm-bindgen-macro/src/ast.rs
@@ -11,6 +11,7 @@ pub struct Program {
     pub enums: Vec<Enum>,
     pub imported_types: Vec<ImportedType>,
     pub structs: Vec<Struct>,
+    pub imported_fields: Vec<ImportField>,
 }
 
 pub struct Export {
@@ -62,6 +63,13 @@ pub struct ImportedType {
     pub name: syn::Ident,
 }
 
+pub struct ImportField {
+    pub vis: syn::Visibility,
+    pub ty: syn::Type,
+    pub module: Option<String>,
+    pub name: syn::Ident,
+}
+
 pub enum Type {
     // special
     Vector(VectorType, bool),
@@ -208,6 +216,7 @@ impl Program {
             match item {
                 syn::ForeignItem::Fn(f) => self.push_foreign_fn(f, &opts),
                 syn::ForeignItem::Type(t) => self.push_foreign_ty(t, &opts),
+                syn::ForeignItem::Static(s) => self.push_foreign_static(s, &opts),
                 _ => panic!("only foreign functions/types allowed for now"),
             }
         }
@@ -341,6 +350,20 @@ impl Program {
         });
     }
 
+    pub fn push_foreign_static(&mut self,
+                               f: syn::ForeignItemStatic,
+                               module_opts: &BindgenAttrs) {
+        if f.mutability.is_some() {
+            panic!("cannot import mutable globals yet")
+        }
+        self.imported_fields.push(ImportField {
+            module: module_opts.module().map(|s| s.to_string()),
+            ty: *f.ty,
+            vis: f.vis,
+            name: f.ident
+        });
+    }
+
     pub fn literal(&self, dst: &mut Tokens) -> usize {
         let mut tmp = Tokens::new();
         let cnt = {
@@ -792,3 +815,12 @@ impl ToTokens for VectorType {
         me.to_tokens(tokens);
     }
 }
+
+impl ImportField {
+    pub fn shared(&self) -> shared::ImportField {
+        shared::ImportField {
+            module: self.module.clone(),
+            name: self.name.to_string(),
+        }
+    }
+}
diff --git a/crates/wasm-bindgen-macro/src/lib.rs b/crates/wasm-bindgen-macro/src/lib.rs
index e65dbd35..c48b7df3 100755
--- a/crates/wasm-bindgen-macro/src/lib.rs
+++ b/crates/wasm-bindgen-macro/src/lib.rs
@@ -78,6 +78,9 @@ impl ToTokens for ast::Program {
         for it in self.imported_types.iter() {
             it.to_tokens(tokens);
         }
+        for it in self.imported_fields.iter() {
+            it.to_tokens(tokens);
+        }
 
         // Generate a static which will eventually be what lives in a custom section
         // of the wasm executable. For now it's just a plain old static, but we'll
@@ -591,3 +594,28 @@ impl ToTokens for ast::Enum {
         }).to_tokens(into);
     }
 }
+
+impl ToTokens for ast::ImportField {
+    fn to_tokens(&self, into: &mut Tokens) {
+        let name = self.name;
+        let ty = &self.ty;
+        let shim_name = syn::Ident::from(self.shared().shim_name());
+        let vis = &self.vis;
+        (my_quote! {
+            #vis static #name: ::wasm_bindgen::JsStatic<#ty> = {
+                fn init() -> #ty {
+                    extern {
+                        fn #shim_name() -> u32;
+                    }
+                    unsafe {
+                        ::wasm_bindgen::convert::WasmBoundary::from_js(#shim_name())
+                    }
+                }
+                ::wasm_bindgen::JsStatic {
+                    __inner: ::std::cell::UnsafeCell::new(None),
+                    __init: init,
+                }
+            };
+        }).to_tokens(into);
+    }
+}
diff --git a/crates/wasm-bindgen-macro/src/literal.rs b/crates/wasm-bindgen-macro/src/literal.rs
index 4f3f6a0e..8e682009 100644
--- a/crates/wasm-bindgen-macro/src/literal.rs
+++ b/crates/wasm-bindgen-macro/src/literal.rs
@@ -107,7 +107,8 @@ impl Literal for ast::Program {
     fn literal(&self, a: &mut LiteralBuilder) {
         a.fields(&[
             ("exports", &|a| a.list_of(&self.exports)),
-            ("imports", &|a| a.list_of(&self.imports)),
+            ("imported_functions", &|a| a.list_of(&self.imports)),
+            ("imported_fields", &|a| a.list_of(&self.imported_fields)),
             ("enums", &|a| a.list_of(&self.enums)),
             ("custom_type_names", &|a| {
                 let names = self.exports
@@ -271,3 +272,15 @@ impl Literal for ast::Variant {
         ])
     }
 }
+
+impl Literal for ast::ImportField {
+    fn literal(&self, a: &mut LiteralBuilder) {
+        a.fields(&[
+            ("name", &|a| a.str(self.name.as_ref())),
+            ("module", &|a| match self.module {
+                Some(ref s) => a.str(s),
+                None => a.append("null"),
+            }),
+        ])
+    }
+}
diff --git a/crates/wasm-bindgen-shared/src/lib.rs b/crates/wasm-bindgen-shared/src/lib.rs
index 89d57375..b3ec75b8 100644
--- a/crates/wasm-bindgen-shared/src/lib.rs
+++ b/crates/wasm-bindgen-shared/src/lib.rs
@@ -11,7 +11,8 @@ pub const SCHEMA_VERSION: &str = "0";
 pub struct Program {
     pub exports: Vec<Export>,
     pub enums: Vec<Enum>,
-    pub imports: Vec<Import>,
+    pub imported_functions: Vec<Import>,
+    pub imported_fields: Vec<ImportField>,
     pub custom_type_names: Vec<CustomTypeName>,
     pub version: String,
     pub schema_version: String,
@@ -30,6 +31,12 @@ pub struct Import {
     pub function: Function,
 }
 
+#[derive(Deserialize)]
+pub struct ImportField {
+    pub module: Option<String>,
+    pub name: String,
+}
+
 #[derive(Deserialize)]
 pub struct Export {
     pub class: Option<String>,
@@ -148,3 +155,9 @@ pub fn version() -> String {
     }
     return v
 }
+
+impl ImportField {
+    pub fn shim_name(&self) -> String {
+        format!("__wbg_field_import_shim_{}", self.name)
+    }
+}
diff --git a/src/lib.rs b/src/lib.rs
index 9cef30bf..deb1e076 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -9,8 +9,12 @@
 
 extern crate wasm_bindgen_macro;
 
+use std::cell::UnsafeCell;
+use std::ops::Deref;
 use std::ptr;
 
+use convert::WasmBoundary;
+
 /// A module which is typically glob imported from:
 ///
 /// ```
@@ -243,6 +247,49 @@ impl Drop for JsValue {
     }
 }
 
+/// Wrapper type for imported statics.
+///
+/// This type is used whenever a `static` is imported from a JS module, for
+/// example this import:
+///
+/// ```ignore
+/// #[wasm_bindgen]
+/// extern {
+///     static console: JsValue;
+/// }
+/// ```
+///
+/// will generate in Rust a value that looks like:
+///
+/// ```ignore
+/// static console: JsStatic<JsValue> = ...;
+/// ```
+///
+/// This type implements `Deref` to the inner type so it's typically used as if
+/// it were `&T`.
+pub struct JsStatic<T> {
+    #[doc(hidden)]
+    pub __inner: UnsafeCell<Option<T>>,
+    #[doc(hidden)]
+    pub __init: fn() -> T,
+}
+
+unsafe impl<T: Sync> Sync for JsStatic<T> {}
+unsafe impl<T: Send> Send for JsStatic<T> {}
+
+impl<T: WasmBoundary> Deref for JsStatic<T> {
+    type Target = T;
+    fn deref(&self) -> &T {
+        unsafe {
+            (*self.__inner.get()).get_or_insert_with(|| {
+                assert!(T::DESCRIPTOR == JsValue::DESCRIPTOR,
+                        "only JS values can be imported as statics for now");
+                (self.__init)()
+            })
+        }
+    }
+}
+
 /// Throws a JS exception.
 ///
 /// This function will throw a JS exception with the message provided. The
diff --git a/tests/imports.rs b/tests/imports.rs
index 0e8cef3a..6bcfd939 100644
--- a/tests/imports.rs
+++ b/tests/imports.rs
@@ -278,3 +278,35 @@ fn free_imports() {
         "#)
         .test();
 }
+
+#[test]
+fn import_a_field() {
+    test_support::project()
+        .file("src/lib.rs", r#"
+            #![feature(proc_macro)]
+
+            extern crate wasm_bindgen;
+
+            use wasm_bindgen::prelude::*;
+
+            #[wasm_bindgen(module = "./test")]
+            extern {
+                static IMPORT: JsValue;
+            }
+
+            #[wasm_bindgen]
+            pub fn run() {
+                assert_eq!(IMPORT.as_f64(), Some(1.0));
+            }
+        "#)
+        .file("test.ts", r#"
+            import { run } from "./out";
+
+            export const IMPORT = 1.0;
+
+            export function test() {
+                run();
+            }
+        "#)
+        .test();
+}