diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2018 Mihai Giurgeanu
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/src/Streaming/UDP.hs b/src/Streaming/UDP.hs
new file mode 100644
--- /dev/null
+++ b/src/Streaming/UDP.hs
@@ -0,0 +1,120 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+{-|
+Module          : Streaming.UDP
+Description     : Simple fire-and-forget UDP components for Streaming library
+Copyright       : (c) 2018 Mihai Giurgeanu
+Stability       : experimental
+Portability     : GHC
+-}
+
+module Streaming.UDP
+  ( fromUDP,
+    fromSocket,
+    fromIOSocket,
+    toUDP,
+    toSocket,
+    toIOSocket,
+  ) where
+
+import           Streaming (Of, Stream, lift)
+import qualified Streaming.Prelude as S
+import           Network.Socket (Socket,
+                                 SockAddr(SockAddrInet),
+                                 PortNumber,
+                                 setSocketOption)
+import qualified Network.Socket as Socket
+import           Network.Socket.ByteString (recvFrom, send)
+import           Control.Monad.IO.Class (MonadIO, liftIO)
+import           Control.Monad.Trans.Resource (MonadResource, allocate)
+import           Data.ByteString (ByteString)
+
+
+-- | gets an ip adress, a port and stream of strict `ByteString`s and
+-- sends all the `ByteString`s to UDP socket
+toUDP :: (MonadResource m) => String -> PortNumber -> Stream (Of ByteString) m r -> m r
+toUDP host port = toIOSocket (udpSocket host port SinkSocket)
+
+-- | Stream all incoming data to the given connected 'Socket'. Note that this function will
+-- not automatically close the 'Socket' when processing completes.
+toSocket :: (MonadIO m) => Socket -> Stream (Of ByteString) m r -> m r
+toSocket s = loop . S.next
+  where
+    loop :: (MonadIO m) => m (Either r (ByteString, Stream (Of ByteString) m r)) -> m r
+    loop m = m >>= either return loop'
+    loop' :: MonadIO m => (ByteString, Stream (Of ByteString) m r) -> m r
+    loop' (msg, str') = liftIO (send s msg) >> (loop $ S.next str')
+                        -- since we are sending a datagram, can't use sendAll; ignore the value returned by send
+
+-- | An alternative to 'toSocket'. Instead of taking a pre-opened 'Socket', it
+-- takes an action that returns a connected 'Socket' , so that it can open it
+-- only when needed and close it as soon as possible.
+toIOSocket :: (MonadResource m) => IO Socket -> Stream (Of ByteString) m r -> m r
+toIOSocket connectAction str = do
+  (_, s) <- allocate connectAction Socket.close
+  toSocket s str
+
+
+-- | Fire-and-forget style UDP source. It will attempt to listen on the
+-- specified interface and port, and if it succeeds it can read contents
+-- being sent to that interface and port.
+-- It streams a pair of (message, source-address) allowing the downstream
+-- to know who sent the message. 
+fromUDP :: (MonadResource m)
+        => String               -- ^ address to bind to
+        -> PortNumber           -- ^ port number to bind to
+        -> Int                  -- ^ maximum size of a datagram
+        -> Stream (Of (ByteString, SockAddr)) m r
+fromUDP host port sz =
+  fromIOSocket (udpSocket host port SourceSocket) sz
+
+-- | Stream the contents of a bound 'Socket' as binary data. Note that this function will
+-- not automatically close the 'Socket' when processing completes, since it did not acquire
+-- the 'Socket' in the first place.
+fromSocket :: (MonadIO m)
+           => Socket                                 -- ^ the socket
+           -> Int                                    -- ^ max lenght of a datagram
+           -> Stream (Of (ByteString, SockAddr)) m r -- ^ the resulting stream of messages
+fromSocket s sz = loop
+  where loop = do
+          msg <- liftIO $ recvFrom s sz
+          S.yield msg
+          loop
+
+-- | An alternative to 'fromSocket'. Instead of taking a pre-bound 'Socket',
+-- it takes an action that opens and binds a Socket, so that it can open it
+-- only when needed and close it as soon as possible.
+fromIOSocket :: (MonadResource m)
+             => IO Socket                              -- ^ the 'IO' action to create the UDP socket
+             -> Int                                    -- ^ max length of a datagram
+             -> Stream (Of (ByteString, SockAddr)) m r -- ^ the resulting stream of messages
+fromIOSocket bindAction sz = do
+  (_, s) <- lift $ allocate bindAction Socket.close
+  fromSocket s sz
+
+-- | Given a host, port and 'SocketType', create a socket and
+-- 'Network.Socket.connect' or 'Network.Socket.bind' to the address pair.
+udpSocket
+    :: String -- ^ IP address to host
+    -> PortNumber
+    -> SocketType
+    -> IO Socket
+udpSocket host port socketType =  do
+    socket <- Socket.socket Socket.AF_INET Socket.Datagram Socket.defaultProtocol
+    setSocketOption socket Socket.ReusePort 1
+    address <- Socket.inet_addr host
+    socketMode socketType socket (SockAddrInet port address)
+    return socket
+
+-- | A type to distinguish when we want to read and write from sockets,
+-- simplifying the implementation
+data SocketType
+    = SourceSocket -- ^ source socket, should 'Network.Socket.bind'
+    | SinkSocket   -- ^ sink socket, should 'Network.Socket.connect'
+
+-- | Use either 'Network.Socket.bind' or 'Network.Socket.connect' depending on the 'SocketType'
+socketMode :: SocketType -> Socket -> SockAddr -> IO ()
+socketMode socketType =
+    case socketType of
+        SourceSocket -> Socket.bind
+        SinkSocket -> Socket.connect
diff --git a/udp-streaming.cabal b/udp-streaming.cabal
new file mode 100644
--- /dev/null
+++ b/udp-streaming.cabal
@@ -0,0 +1,34 @@
+-- This file has been generated from package.yaml by hpack version 0.20.0.
+--
+-- see: https://github.com/sol/hpack
+--
+-- hash: 7e911d679bae02bfce07a28bc4e8d4e264414212bd4957071ee7f7b7779de1c4
+
+name:           udp-streaming
+version:        0.1.0.0
+synopsis:       Simple fire-and-forget udp Streaming components modelled after udp-conduit
+category:       Network, Streaming
+stability:      experimental
+homepage:       https://hub.darcs.net/mihaigiurgeanu/udp-streaming
+author:         Mihai Giurgeanu
+maintainer:     mihai.giurgeanu@gmail.com
+copyright:      (c) 2018 Mihai Giurgeanu
+license:        MIT
+license-file:   LICENSE
+build-type:     Simple
+cabal-version:  >= 1.10
+
+library
+  hs-source-dirs:
+      src
+  build-depends:
+      base >=4.6 && <5.0
+    , bytestring >=0.10 && <0.11
+    , network >=2.0 && <3
+    , resourcet >=1.2 && <2
+    , streaming >=0.2 && <0.3
+  exposed-modules:
+      Streaming.UDP
+  other-modules:
+      Paths_udp_streaming
+  default-language: Haskell2010
