diff --git a/Makefile.objs b/Makefile.objs
index 3c7abca..360500d 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -68,8 +68,11 @@ endif
 common-obj-y = $(block-obj-y) blockdev.o blockdev-nbd.o block/
 common-obj-y += net.o net/
 common-obj-y += qom/
-common-obj-y += readline.o console.o cursor.o
-common-obj-y += qemu-pixman.o
+common-obj-y += readline.o
+common-obj-$(CONFIG_GRAPHICS) += console.o cursor.o qemu-pixman.o
+ifneq ($(CONFIG_GRAPHICS),y)
+common-obj-y += no-console.o
+endif
 common-obj-y += $(oslib-obj-y)
 common-obj-$(CONFIG_WIN32) += os-win32.o
 common-obj-$(CONFIG_POSIX) += os-posix.o
diff --git a/configure b/configure
index 38b1cc6..6cb73e6 100755
--- a/configure
+++ b/configure
@@ -223,6 +223,7 @@ libiscsi=""
 coroutine=""
 seccomp=""
 glusterfs=""
+graphics="yes"
 
 # parse CC options first
 for opt do
@@ -880,6 +881,14 @@ for opt do
   ;;
   --enable-glusterfs) glusterfs="yes"
   ;;
+  --disable-graphics)
+    graphics="no"
+    vnc="no"
+    spice="no"
+    curses="no"
+  ;;
+  --enable-graphics) graphics="yes"
+  ;;
   *) echo "ERROR: unknown option $opt"; show_help="yes"
   ;;
   esac
@@ -1128,6 +1137,8 @@ echo "  --with-coroutine=BACKEND coroutine backend. Supported options:"
 echo "                           gthread, ucontext, sigaltstack, windows"
 echo "  --enable-glusterfs       enable GlusterFS backend"
 echo "  --disable-glusterfs      disable GlusterFS backend"
+echo "  --enable-graphics        enable graphics support (default)"
+echo "  --disable-graphics       disable graphics support"
 echo ""
 echo "NOTE: The object files are built at the place where configure is launched"
 exit 1
@@ -2126,6 +2137,14 @@ fi
 ##########################################
 # pixman support probe
 
+if test "$graphics" = "no"; then
+  pixman="not needed"
+  if test "$vnc" = "yes" -o "$spice" = "yes"; then
+    echo "ERROR: graphics disabled but vnc or spice enabled"
+    exit 1
+  fi
+fi
+
 if test "$pixman" = ""; then
   if $pkg_config --atleast-version=0.18.4 pixman-1 > /dev/null 2>&1; then
     pixman="system"
@@ -2136,7 +2155,7 @@ fi
 if test "$pixman" = "system"; then
   pixman_cflags=`$pkg_config --cflags pixman-1 2>/dev/null`
   pixman_libs=`$pkg_config --libs pixman-1 2>/dev/null`
-else
+elif test "$pixman" != "not needed"; then
   if test ! -d ${source_path}/pixman/pixman; then
     echo "ERROR: pixman not present (or older than 0.18.4). Your options:"
     echo "  (1) Preferred: Install the pixman devel package (any recent"
@@ -3257,6 +3276,7 @@ echo "build guest agent $guest_agent"
 echo "seccomp support   $seccomp"
 echo "coroutine backend $coroutine_backend"
 echo "GlusterFS support $glusterfs"
+echo "graphics          $graphics"
 
 if test "$sdl_too_old" = "yes"; then
 echo "-> Your SDL version is too old - please upgrade to have SDL support"
@@ -3603,6 +3623,10 @@ if test "$glusterfs" = "yes" ; then
   echo "CONFIG_GLUSTERFS=y" >> $config_host_mak
 fi
 
+if test "$graphics" = "yes" ; then
+  echo "CONFIG_GRAPHICS=y" >> $config_host_mak
+fi
+
 # USB host support
 case "$usb" in
 linux)
diff --git a/console.h b/console.h
index 50a0512..49d8469 100644
--- a/console.h
+++ b/console.h
@@ -120,8 +120,10 @@ struct PixelFormat {
 };
 
 struct DisplaySurface {
+#ifdef CONFIG_GRAPHICS
     pixman_format_code_t format;
     pixman_image_t *image;
+#endif
     uint8_t flags;
 
     struct PixelFormat pf;
@@ -340,6 +342,7 @@ static inline bool dpy_cursor_define_supported(struct DisplayState *s)
     return false;
 }
 
+#ifdef CONFIG_GRAPHICS
 static inline int ds_get_linesize(DisplayState *ds)
 {
     return pixman_image_get_stride(ds->surface->image);
@@ -401,6 +404,7 @@ static inline int ds_get_bmask(DisplayState *ds)
 {
     return ds->surface->pf.bmask;
 }
+#endif
 
 #ifdef CONFIG_CURSES
 #include <curses.h>
diff --git a/hw/Makefile.objs b/hw/Makefile.objs
index d581d8d..6297759 100644
--- a/hw/Makefile.objs
+++ b/hw/Makefile.objs
@@ -127,12 +127,14 @@ common-obj-y += sysbus.o isa-bus.o
 common-obj-y += qdev-addr.o
 
 # VGA
+ifeq ($(CONFIG_GRAPHICS), y)
 common-obj-$(CONFIG_VGA_PCI) += vga-pci.o
 common-obj-$(CONFIG_VGA_ISA) += vga-isa.o
 common-obj-$(CONFIG_VGA_ISA_MM) += vga-isa-mm.o
 common-obj-$(CONFIG_VMWARE_VGA) += vmware_vga.o
 common-obj-$(CONFIG_VMMOUSE) += vmmouse.o
 common-obj-$(CONFIG_VGA_CIRRUS) += cirrus_vga.o
+endif
 
 common-obj-$(CONFIG_RC4030) += rc4030.o
 common-obj-$(CONFIG_DP8393X) += dp8393x.o
@@ -200,7 +202,9 @@ obj-$(CONFIG_SOFTMMU) += vhost_net.o
 obj-$(CONFIG_VHOST_NET) += vhost.o
 obj-$(CONFIG_REALLY_VIRTFS) += 9pfs/
 obj-$(CONFIG_NO_PCI) += pci-stub.o
+ifeq ($(CONFIG_GRAPHICS), y)
 obj-$(CONFIG_VGA) += vga.o
+endif
 obj-$(CONFIG_SOFTMMU) += device-hotplug.o
 obj-$(CONFIG_XEN) += xen_domainbuild.o xen_machine_pv.o
 
diff --git a/no-console.c b/no-console.c
new file mode 100644
index 0000000..f4e418f
--- /dev/null
+++ b/no-console.c
@@ -0,0 +1,8 @@
+#include "qemu-common.h"
+#include "error.h"
+#include "qmp-commands.h"
+
+void qmp_screendump(const char *filename, Error **errp)
+{
+  error_setg(errp, "device doesn't support screendump\n");
+}
diff --git a/qemu-char.c b/qemu-char.c
index 242b799..e488e2c 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -2735,7 +2735,9 @@ static const struct {
     { .name = "socket",    .open = qemu_chr_open_socket },
     { .name = "udp",       .open = qemu_chr_open_udp },
     { .name = "msmouse",   .open = qemu_chr_open_msmouse },
+#ifdef CONFIG_GRAPHICS
     { .name = "vc",        .open = text_console_init },
+#endif
 #ifdef _WIN32
     { .name = "file",      .open = qemu_chr_open_win_file_out },
     { .name = "pipe",      .open = qemu_chr_open_win_pipe },
diff --git a/qemu-pixman.c b/qemu-pixman.c
index e46e180..821a525 100644
--- a/qemu-pixman.c
+++ b/qemu-pixman.c
@@ -3,6 +3,7 @@
  * See the COPYING file in the top-level directory.
  */
 
+#include "qemu-common.h"
 #include "qemu-pixman.h"
 
 int qemu_pixman_get_type(int rshift, int gshift, int bshift)
diff --git a/qemu-pixman.h b/qemu-pixman.h
index bee55eb..0844816 100644
--- a/qemu-pixman.h
+++ b/qemu-pixman.h
@@ -6,6 +6,8 @@
 #ifndef QEMU_PIXMAN_H
 #define QEMU_PIXMAN_H
 
+#ifdef CONFIG_GRAPHICS
+
 #include <pixman.h>
 
 #include "console.h"
@@ -36,4 +38,6 @@ pixman_image_t *qemu_pixman_mirror_create(pixman_format_code_t format,
                                           pixman_image_t *image);
 void qemu_pixman_image_unref(pixman_image_t *image);
 
+#endif /* CONFIG_GRAPHICS */
+
 #endif /* QEMU_PIXMAN_H */
diff --git a/ui/Makefile.objs b/ui/Makefile.objs
index adc07be..91cca0b 100644
--- a/ui/Makefile.objs
+++ b/ui/Makefile.objs
@@ -8,7 +8,9 @@ vnc-obj-y += vnc-jobs.o
 
 common-obj-y += keymaps.o
 common-obj-$(CONFIG_SPICE) += spice-core.o spice-input.o spice-display.o
+ifeq ($(CONFIG_GRAPHICS),y)
 common-obj-$(CONFIG_SDL) += sdl.o sdl_zoom.o x_keymap.o
+endif
 common-obj-$(CONFIG_COCOA) += cocoa.o
 common-obj-$(CONFIG_CURSES) += curses.o
 common-obj-$(CONFIG_VNC) += $(vnc-obj-y)
diff --git a/ui/vnc.h b/ui/vnc.h
index 6141e88..60b19cd 100644
--- a/ui/vnc.h
+++ b/ui/vnc.h
@@ -41,6 +41,8 @@
 #include "vnc-palette.h"
 #include "vnc-enc-zrle.h"
 
+#ifdef CONFIG_VNC
+
 // #define _VNC_DEBUG 1
 
 #ifdef _VNC_DEBUG
@@ -560,4 +562,6 @@ int vnc_zrle_send_framebuffer_update(VncState *vs, int x, int y, int w, int h);
 int vnc_zywrle_send_framebuffer_update(VncState *vs, int x, int y, int w, int h);
 void vnc_zrle_clear(VncState *vs);
 
+#endif
+
 #endif /* __QEMU_VNC_H */
diff --git a/vl.c b/vl.c
index a3ab384..5679db3 100644
--- a/vl.c
+++ b/vl.c
@@ -180,8 +180,14 @@ int main(int argc, char **argv)
 static const char *data_dir;
 const char *bios_name = NULL;
 enum vga_retrace_method vga_retrace_method = VGA_RETRACE_DUMB;
+
+#ifdef CONFIG_GRAPHICS
 DisplayType display_type = DT_DEFAULT;
 static int display_remote;
+#else
+DisplayType display_type = DT_NOGRAPHIC;
+#endif
+
 const char* keyboard_layout = NULL;
 ram_addr_t ram_size;
 const char *mem_path = NULL;
@@ -2532,7 +2538,9 @@ int main(int argc, char **argv, char **envp)
     const char *initrd_filename;
     const char *kernel_filename, *kernel_cmdline;
     char boot_devices[33] = "cad"; /* default to HD->floppy->CD-ROM */
+#ifdef CONFIG_GRAPHICS
     DisplayState *ds;
+#endif
     int cyls, heads, secs, translation;
     QemuOpts *hda_opts = NULL, *opts, *machine_opts;
     QemuOptsList *olist;
@@ -3887,6 +3895,7 @@ int main(int argc, char **argv, char **envp)
 
     net_check_clients();
 
+#ifdef CONFIG_GRAPHICS
     /* just use the first displaystate for the moment */
     ds = get_displaystate();
 
@@ -3927,7 +3936,7 @@ int main(int argc, char **argv, char **envp)
     default:
         break;
     }
-
+#endif /* CONFIG_GRAPHICS */
     /* must be after terminal init, SDL library changes signal handlers */
     os_setup_signal_handling();
 
@@ -3954,9 +3963,10 @@ int main(int argc, char **argv, char **envp)
         qemu_spice_display_init(ds);
     }
 #endif
-
+#ifdef CONFIG_GRAPHICS
     /* display setup */
     text_consoles_set_display(ds);
+#endif
 
     if (foreach_device_config(DEV_GDB, gdbserver_start) < 0) {
         exit(1);
