diff --git a/include/qapi/json-output-visitor.h b/include/qapi/json-output-visitor.h
index 5be5a13..e5e16e6 100644
--- a/include/qapi/json-output-visitor.h
+++ b/include/qapi/json-output-visitor.h
@@ -15,7 +15,7 @@

 typedef struct JsonOutputVisitor JsonOutputVisitor;

-JsonOutputVisitor *json_output_visitor_new(void);
+JsonOutputVisitor *json_output_visitor_new(bool pretty);
 void json_output_visitor_cleanup(JsonOutputVisitor *v);
 void json_output_visitor_reset(JsonOutputVisitor *v);

diff --git a/qapi/json-output-visitor.c b/qapi/json-output-visitor.c
index 0d759c4..a939af1 100644
--- a/qapi/json-output-visitor.c
+++ b/qapi/json-output-visitor.c
@@ -18,6 +18,7 @@
 struct JsonOutputVisitor {
     Visitor visitor;
     QString *str;
+    bool pretty;
     bool comma;
     int depth;
 };
@@ -33,10 +34,13 @@ static void json_output_name(JsonOutputVisitor *jov, const char *name)
         jov->str = qstring_new();
     }
     if (jov->comma) {
-        qstring_append(jov->str, ", ");
+        qstring_append(jov->str, jov->pretty ? "," : ", ");
     } else {
         jov->comma = true;
     }
+    if (jov->pretty && jov->depth) {
+        qstring_append_format(jov->str, "\n%*s", 4 * jov->depth, "");
+    }
     if (name && jov->depth) {
         qstring_append_json_string(jov->str, name);
         qstring_append(jov->str, ": ");
@@ -59,6 +63,9 @@ static void json_output_end_struct(Visitor *v)
     JsonOutputVisitor *jov = to_jov(v);
     assert(jov->depth);
     jov->depth--;
+    if (jov->pretty) {
+        qstring_append_format(jov->str, "\n%*s", 4 * jov->depth, "");
+    }
     qstring_append(jov->str, "}");
     jov->comma = true;
 }
@@ -85,6 +92,9 @@ static void json_output_end_list(Visitor *v)
     JsonOutputVisitor *jov = to_jov(v);
     assert(jov->depth);
     jov->depth--;
+    if (jov->pretty) {
+        qstring_append_format(jov->str, "\n%*s", 4 * jov->depth, "");
+    }
     qstring_append(jov->str, "]");
     jov->comma = true;
 }
@@ -134,7 +144,15 @@ static void json_output_type_any(Visitor *v, QObject **obj, const char *name,
                                  Error **errp)
 {
     JsonOutputVisitor *jov = to_jov(v);
-    QString *str = qobject_to_json(*obj);
+    QString *str;
+
+    if (jov->pretty) {
+        char *prefix = g_strdup_printf("%*s", 4 * jov->depth, "");
+        str = qobject_to_json_pretty_prefix(*obj, prefix);
+        g_free(prefix);
+    } else {
+        str = qobject_to_json(*obj);
+    }
     assert(str);
     json_output_name(jov, name);
     qstring_append(jov->str, qstring_get_str(str));
@@ -178,11 +196,12 @@ void json_output_visitor_cleanup(JsonOutputVisitor *v)
     g_free(v);
 }

-JsonOutputVisitor *json_output_visitor_new(void)
+JsonOutputVisitor *json_output_visitor_new(bool pretty)
 {
     JsonOutputVisitor *v;

     v = g_malloc0(sizeof(*v));
+    v->pretty = pretty;

     v->visitor.start_struct = json_output_start_struct;
     v->visitor.end_struct = json_output_end_struct;
diff --git a/qjson.c b/qjson.c
index 6aac46d..9debf1d 100644
--- a/qjson.c
+++ b/qjson.c
@@ -84,7 +84,7 @@ void qjson_finish(QJSON *json)
 static void qjson_initfn(Object *obj)
 {
     QJSON *json = QJSON(obj);
-    json->jov = json_output_visitor_new();
+    json->jov = json_output_visitor_new(false);
 }

 static void qjson_finalizefn(Object *obj)
diff --git a/tests/test-json-output-visitor.c b/tests/test-json-output-visitor.c
index e47571a..bfa21f7 100644
--- a/tests/test-json-output-visitor.c
+++ b/tests/test-json-output-visitor.c
@@ -21,9 +21,10 @@ typedef struct TestOutputVisitorData {
 } TestOutputVisitorData;

 static void visitor_output_setup(TestOutputVisitorData *data,
-                                 const void *unused)
+                                 const void *arg)
 {
-    data->jov = json_output_visitor_new();
+    const bool *pretty = arg;
+    data->jov = json_output_visitor_new(*pretty);
     g_assert(data->jov);

     data->ov = json_output_get_visitor(data->jov);
@@ -149,8 +150,9 @@ static void test_visitor_out_struct(TestOutputVisitorData *data,
 }

 static void test_visitor_out_struct_nested(TestOutputVisitorData *data,
-                                           const void *unused)
+                                           const void *arg)
 {
+    const bool *pretty = arg;
     int64_t value = 42;
     UserDefTwo *ud2;
     const char *string = "user def string";
@@ -180,27 +182,51 @@ static void test_visitor_out_struct_nested(TestOutputVisitorData *data,
     visit_type_UserDefTwo(data->ov, &ud2, "unused", &error_abort);

     out = json_output_get_string(data->jov);
-    g_assert_cmpstr(out, ==,
-                    "{"
-                     "\"string0\": \"forty two\", "
-                     "\"dict1\": {"
-                      "\"string1\": \"forty three\", "
-                      "\"dict2\": {"
-                       "\"userdef\": {"
-                        "\"integer\": 42, "
-                        "\"string\": \"user def string\""
-                        "}, "
-                       "\"string\": \"forty four\""
-                       "}, "
-                      "\"dict3\": {"
-                       "\"userdef\": {"
-                        "\"integer\": 42, "
-                        "\"string\": \"user def string\""
-                        "}, "
-                      "\"string\": \"forty five\""
-                      "}"
-                     "}"
-                    "}");
+    if (*pretty) {
+        g_assert_cmpstr(out, ==,
+                        "{\n"
+                        "    \"string0\": \"forty two\",\n"
+                        "    \"dict1\": {\n"
+                        "        \"string1\": \"forty three\",\n"
+                        "        \"dict2\": {\n"
+                        "            \"userdef\": {\n"
+                        "                \"integer\": 42,\n"
+                        "                \"string\": \"user def string\"\n"
+                        "            },\n"
+                        "            \"string\": \"forty four\"\n"
+                        "        },\n"
+                        "        \"dict3\": {\n"
+                        "            \"userdef\": {\n"
+                        "                \"integer\": 42,\n"
+                        "                \"string\": \"user def string\"\n"
+                        "            },\n"
+                        "            \"string\": \"forty five\"\n"
+                        "        }\n"
+                        "    }\n"
+                        "}");
+    } else {
+        g_assert_cmpstr(out, ==,
+                        "{"
+                         "\"string0\": \"forty two\", "
+                         "\"dict1\": {"
+                          "\"string1\": \"forty three\", "
+                          "\"dict2\": {"
+                           "\"userdef\": {"
+                            "\"integer\": 42, "
+                            "\"string\": \"user def string\""
+                            "}, "
+                           "\"string\": \"forty four\""
+                           "}, "
+                          "\"dict3\": {"
+                           "\"userdef\": {"
+                            "\"integer\": 42, "
+                            "\"string\": \"user def string\""
+                            "}, "
+                          "\"string\": \"forty five\""
+                          "}"
+                         "}"
+                        "}");
+    }
     qapi_free_UserDefTwo(ud2);
     g_free(out);
 }
@@ -279,16 +305,23 @@ static void test_visitor_out_list(TestOutputVisitorData *data,
 }

 static void test_visitor_out_any(TestOutputVisitorData *data,
-                                 const void *unused)
+                                 const void *arg)
 {
+    const bool *pretty = arg;
     QObject *qobj;
     QDict *qdict;
     char *out;

     qobj = QOBJECT(qint_from_int(-42));
+    visit_start_list(data->ov, NULL, NULL, 0, &error_abort);
     visit_type_any(data->ov, &qobj, NULL, &error_abort);
+    visit_end_list(data->ov);
     out = json_output_get_string(data->jov);
-    g_assert_cmpstr(out, ==, "-42");
+    if (*pretty) {
+        g_assert_cmpstr(out, ==, "[\n    -42\n]");
+    } else {
+        g_assert_cmpstr(out, ==, "[-42]");
+    }
     qobject_decref(qobj);
     g_free(out);

@@ -297,15 +330,30 @@ static void test_visitor_out_any(TestOutputVisitorData *data,
     qdict_put(qdict, "boolean", qbool_from_bool(true));
     qdict_put(qdict, "string", qstring_from_str("foo"));
     qobj = QOBJECT(qdict);
+    visit_start_list(data->ov, NULL, NULL, 0, &error_abort);
     visit_type_any(data->ov, &qobj, NULL, &error_abort);
+    visit_end_list(data->ov);
     qobject_decref(qobj);
     out = json_output_get_string(data->jov);
-    g_assert_cmpstr(out, ==,
-                    "{"
-                     "\"integer\": -42, "
-                     "\"boolean\": true, "
-                     "\"string\": \"foo\""
-                    "}");
+    if (*pretty) {
+        g_assert_cmpstr(out, ==,
+                        "[\n"
+                        "    {\n"
+                        "        \"integer\": -42,\n"
+                        "        \"boolean\": true,\n"
+                        "        \"string\": \"foo\"\n"
+                        "    }\n"
+                        "]");
+    } else {
+        g_assert_cmpstr(out, ==,
+                        "["
+                         "{"
+                          "\"integer\": -42, "
+                          "\"boolean\": true, "
+                          "\"string\": \"foo\""
+                         "}"
+                        "]");
+    }
     g_free(out);
 }

@@ -372,37 +420,53 @@ static void test_visitor_out_empty(TestOutputVisitorData *data,
     g_free(out);
 }

-static void output_visitor_test_add(const char *testpath,
+static void output_visitor_test_add(const char *testpath, bool *data,
                                     void (*test_func)(TestOutputVisitorData *,
                                                       const void *))
 {
-    g_test_add(testpath, TestOutputVisitorData, NULL, visitor_output_setup,
+    g_test_add(testpath, TestOutputVisitorData, data, visitor_output_setup,
                test_func, visitor_output_teardown);
 }

 int main(int argc, char **argv)
 {
+    bool plain = false;
+    bool pretty = true;
+
     g_test_init(&argc, &argv, NULL);

-    output_visitor_test_add("/visitor/json/int", test_visitor_out_int);
-    output_visitor_test_add("/visitor/json/bool", test_visitor_out_bool);
-    output_visitor_test_add("/visitor/json/number", test_visitor_out_number);
-    output_visitor_test_add("/visitor/json/string", test_visitor_out_string);
-    output_visitor_test_add("/visitor/json/enum", test_visitor_out_enum);
-    output_visitor_test_add("/visitor/json/enum-errors",
+    output_visitor_test_add("/visitor/json/int", &plain,
+                            test_visitor_out_int);
+    output_visitor_test_add("/visitor/json/bool", &plain,
+                            test_visitor_out_bool);
+    output_visitor_test_add("/visitor/json/number", &plain,
+                            test_visitor_out_number);
+    output_visitor_test_add("/visitor/json/string", &plain,
+                            test_visitor_out_string);
+    output_visitor_test_add("/visitor/json/enum", &plain,
+                            test_visitor_out_enum);
+    output_visitor_test_add("/visitor/json/enum-errors", &plain,
                             test_visitor_out_enum_errors);
-    output_visitor_test_add("/visitor/json/struct", test_visitor_out_struct);
-    output_visitor_test_add("/visitor/json/struct-nested",
+    output_visitor_test_add("/visitor/json/struct", &plain,
+                            test_visitor_out_struct);
+    output_visitor_test_add("/visitor/json/struct-nested", &plain,
                             test_visitor_out_struct_nested);
-    output_visitor_test_add("/visitor/json/struct-errors",
+    output_visitor_test_add("/visitor/json-pretty/struct-nested", &pretty,
+                            test_visitor_out_struct_nested);
+    output_visitor_test_add("/visitor/json/struct-errors", &plain,
                             test_visitor_out_struct_errors);
-    output_visitor_test_add("/visitor/json/list", test_visitor_out_list);
-    output_visitor_test_add("/visitor/json/any", test_visitor_out_any);
-    output_visitor_test_add("/visitor/json/union-flat",
+    output_visitor_test_add("/visitor/json/list", &plain,
+                            test_visitor_out_list);
+    output_visitor_test_add("/visitor/json/any", &plain,
+                            test_visitor_out_any);
+    output_visitor_test_add("/visitor/json-pretty/any", &pretty,
+                            test_visitor_out_any);
+    output_visitor_test_add("/visitor/json/union-flat", &plain,
                             test_visitor_out_union_flat);
-    output_visitor_test_add("/visitor/json/alternate",
+    output_visitor_test_add("/visitor/json/alternate", &plain,
                             test_visitor_out_alternate);
-    output_visitor_test_add("/visitor/json/empty", test_visitor_out_empty);
+    output_visitor_test_add("/visitor/json/empty", &plain,
+                            test_visitor_out_empty);

     g_test_run();

