diff --git a/compile.c b/compile.c
index 69044626..77dfd904 100644
--- a/compile.c
+++ b/compile.c
@@ -371,6 +371,12 @@ block gen_or(block a, block b) {
                                                    gen_const(jv_false())))));
 }
 
+block gen_var_binding(block var, const char* name, block body) {
+  return BLOCK(gen_op_simple(DUP), var,
+               block_bind(gen_op_var_unbound(STOREV, name),
+                          body, OP_HAS_VARIABLE));
+}
+
 block gen_cond(block cond, block iftrue, block iffalse) {
   return BLOCK(gen_op_simple(DUP), cond, 
                gen_condbranch(BLOCK(gen_op_simple(POP), iftrue),
diff --git a/compile.h b/compile.h
index f982e3bf..00a863c6 100644
--- a/compile.h
+++ b/compile.h
@@ -40,6 +40,8 @@ block gen_condbranch(block iftrue, block iffalse);
 block gen_and(block a, block b);
 block gen_or(block a, block b);
 
+block gen_var_binding(block var, const char* name, block body);
+
 block gen_cond(block cond, block iftrue, block iffalse);
 
 block gen_cbinding(const struct cfunction* functions, int nfunctions, block b);
diff --git a/docs/content/3.manual/manual.yml b/docs/content/3.manual/manual.yml
index 7b490659..c85fcd57 100644
--- a/docs/content/3.manual/manual.yml
+++ b/docs/content/3.manual/manual.yml
@@ -121,6 +121,12 @@ sections:
         formatted as a JSON string with quotes. This can be useful for
         making jq filters talk to non-JSON-based systems.
 
+      * `--arg name value`:
+
+        This option passes a value to the jq program as a predefined
+        variable. If you run jq with `--arg foo bar`, then `$foo` is
+        available in the program and has the value `"bar"`.
+
   - title: Basic filters
     entries:
       - title: "`.`"
diff --git a/execute.c b/execute.c
index 22ffadbb..5651dcf5 100644
--- a/execute.c
+++ b/execute.c
@@ -506,13 +506,22 @@ void jq_teardown(jq_state **jq) {
   jv_mem_free(old_jq);
 }
 
-struct bytecode* jq_compile(const char* str) {
+struct bytecode* jq_compile_args(const char* str, jv args) {
+  assert(jv_get_kind(args) == JV_KIND_ARRAY);
   struct locfile locations;
   locfile_init(&locations, str, strlen(str));
   block program;
   struct bytecode* bc = 0;
   int nerrors = jq_parse(&locations, &program);
   if (nerrors == 0) {
+    for (int i=0; i<jv_array_length(jv_copy(args)); i++) {
+      jv arg = jv_array_get(jv_copy(args), i);
+      jv name = jv_object_get(jv_copy(arg), jv_string("name"));
+      jv value = jv_object_get(arg, jv_string("value"));
+      program = gen_var_binding(gen_const(value), jv_string_value(name), program);
+      jv_free(name);
+    }
+    jv_free(args);
     program = builtins_bind(program);
     nerrors = block_compile(program, &locations, &bc);
   }
@@ -522,3 +531,7 @@ struct bytecode* jq_compile(const char* str) {
   locfile_free(&locations);
   return bc;
 }
+
+struct bytecode* jq_compile(const char* str) {
+  return jq_compile_args(str, jv_array());
+}
diff --git a/execute.h b/execute.h
index 1cf14df7..004b66ba 100644
--- a/execute.h
+++ b/execute.h
@@ -3,8 +3,12 @@
 #include "bytecode.h"
 
 
+
 struct bytecode* jq_compile(const char* str);
 
+/* args must be an array of the form [{name:"foo", value:"thing"}, {name:"bar",value:3}] */
+struct bytecode* jq_compile_args(const char* str, jv args);
+
 typedef struct jq_state jq_state;
 enum {JQ_DEBUG_TRACE = 1};
 
diff --git a/main.c b/main.c
index d2c553c0..afdff189 100644
--- a/main.c
+++ b/main.c
@@ -154,6 +154,7 @@ int main(int argc, char* argv[]) {
   ninput_files = 0;
   int further_args_are_files = 0;
   int jq_flags = 0;
+  jv program_arguments = jv_array();
   for (int i=1; i<argc; i++) {
     if (further_args_are_files) {
       input_filenames[ninput_files++] = argv[i];
@@ -184,6 +185,16 @@ int main(int argc, char* argv[]) {
       options |= PROVIDE_NULL;
     } else if (isoption(argv[i], 'f', "from-file")) {
       options |= FROM_FILE;
+    } else if (isoption(argv[i], 0, "arg")) {
+      if (i >= argc - 2) {
+        fprintf(stderr, "%s: --arg takes two parameters (e.g. -a varname value)\n", progname);
+        die();
+      }
+      jv arg = jv_object();
+      arg = jv_object_set(arg, jv_string("name"), jv_string(argv[i+1]));
+      arg = jv_object_set(arg, jv_string("value"), jv_string(argv[i+2]));
+      program_arguments = jv_array_append(program_arguments, arg);
+      i += 2; // skip the next two arguments
     } else if (isoption(argv[i],  0,  "debug-dump-disasm")) {
       options |= DUMP_DISASM;
     } else if (isoption(argv[i],  0,  "debug-trace")) {
@@ -214,10 +225,10 @@ int main(int argc, char* argv[]) {
       jv_free(data);
       return 1;
     }
-    bc = jq_compile(jv_string_value(data));
+    bc = jq_compile_args(jv_string_value(data), program_arguments);
     jv_free(data);
   } else {
-    bc = jq_compile(program);
+    bc = jq_compile_args(program, program_arguments);
   }
   if (!bc) return 1;
 
diff --git a/parser.y b/parser.y
index 92cd9db8..8c663b9b 100644
--- a/parser.y
+++ b/parser.y
@@ -201,9 +201,7 @@ FuncDef Exp %prec ';' {
 } |
 
 Term "as" '$' IDENT '|' Exp {
-  $$ = BLOCK(gen_op_simple(DUP), $1, 
-             block_bind(gen_op_var_unbound(STOREV, jv_string_value($4)), 
-                        $6, OP_HAS_VARIABLE));
+  $$ = gen_var_binding($1, jv_string_value($4), $6);
   jv_free($4);
 } |